Compare commits

..

1 Commits

Author SHA1 Message Date
Stevie Robinson
4dc3d69a11 Fix RemoveHelpTextWarning > RemoveFromDownloadClientHelpTextWarning
(cherry picked from commit 901b6d20841bfcb2a3724fe27b0fbddf5e41d669)
2023-08-12 04:21:38 +00:00
129 changed files with 539 additions and 1986 deletions

3
.gitattributes vendored
View File

@@ -3,7 +3,8 @@
# Explicitly set bash scripts to have unix endings
*.sh text eol=lf
distribution/osx/Readarr text eol=lf
distribution/debian/* text eol=lf
macOS/Readarr text eol=lf
# Custom for Visual Studio
*.cs diff=csharp

View File

@@ -30,6 +30,7 @@ Note that only one type of a given book is supported. If you want both an audiob
[![Wiki](https://img.shields.io/badge/servarr-wiki-181717.svg?maxAge=60)](https://wiki.servarr.com/readarr)
[![Discord](https://img.shields.io/badge/discord-chat-7289DA.svg?maxAge=60)](https://readarr.com/discord)
[![Reddit](https://img.shields.io/badge/reddit-discussion-FF4500.svg?maxAge=60)](https://www.reddit.com/r/readarr)
Note: GitHub Issues are for Bugs and Feature Requests Only

View File

@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '0.3.3'
majorVersion: '0.3.2'
minorVersion: $[counter('minorVersion', 1)]
readarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(readarrVersion)'
@@ -27,10 +27,6 @@ trigger:
include:
- develop
- master
paths:
exclude:
- .github
- src/Readarr.Api.*/openapi.json
pr:
branches:
@@ -38,37 +34,82 @@ pr:
- develop
paths:
exclude:
- .github
- src/NzbDrone.Core/Localization/Core
- src/Readarr.Api.*/openapi.json
stages:
- stage: Setup
displayName: Setup
- stage: Build_Backend_Windows
displayName: Build Backend
dependsOn: []
jobs:
- job:
displayName: Build Variables
- job: Backend
strategy:
matrix:
Windows:
osName: 'Windows'
imageName: ${{ variables.windowsImage }}
enableAnalysis: 'false'
pool:
vmImage: ${{ variables.linuxImage }}
vmImage: $(imageName)
variables:
# Disable stylecop here - linting errors get caught by the analyze task
EnableAnalyzers: $(enableAnalysis)
steps:
# Set the build name properly. The 'name' property won't recursively expand so hack here:
- bash: echo "##vso[build.updatebuildnumber]$READARRVERSION"
displayName: Set Build Name
- checkout: self
submodules: true
fetchDepth: 1
- task: UseDotNet@2
displayName: 'Install .net core'
inputs:
version: $(dotnetVersion)
- bash: |
if [[ $BUILD_REASON == "PullRequest" ]]; then
git diff origin/develop...HEAD --name-only | grep -E "^(src/|azure-pipelines.yml)"
echo $? > not_backend_update
else
echo 0 > not_backend_update
SDK_PATH="${AGENT_TOOLSDIRECTORY}/dotnet/sdk/${DOTNETVERSION}"
BUNDLEDVERSIONS="${SDK_PATH}/Microsoft.NETCoreSdk.BundledVersions.props"
if ! grep -q freebsd-x64 $BUNDLEDVERSIONS; then
sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64;linux-x86/' $BUNDLEDVERSIONS
fi
cat not_backend_update
displayName: Check for Backend File Changes
- publish: not_backend_update
artifact: not_backend_update
displayName: Publish update type
- stage: Build_Backend
displayName: Build Backend
dependsOn: Setup
displayName: Extra Platform Support
- task: Cache@2
inputs:
key: 'nuget | "$(Agent.OS)" | $(Build.SourcesDirectory)/src/Directory.Packages.props'
path: $(nugetCacheFolder)
displayName: Cache NuGet packages
- bash: ./build.sh --backend --enable-bsd
displayName: Build Readarr Backend
env:
NUGET_PACKAGES: $(nugetCacheFolder)
- powershell: Get-ChildItem _output\net6.0*,_output\*.Update\* -Recurse | Where { $_.Fullname -notlike "*\publish\*" -and $_.attributes -notlike "*directory*" } | Remove-Item
displayName: Clean up intermediate output
- publish: $(outputFolder)
artifact: '$(osName)Backend'
displayName: Publish Backend
- publish: '$(testsFolder)/net6.0/win-x64/publish'
artifact: win-x64-tests
displayName: Publish win-x64 Test Package
- publish: '$(testsFolder)/net6.0/linux-x64/publish'
artifact: linux-x64-tests
displayName: Publish linux-x64 Test Package
- publish: '$(testsFolder)/net6.0/linux-x86/publish'
artifact: linux-x86-tests
displayName: Publish linux-x86 Test Package
- publish: '$(testsFolder)/net6.0/linux-musl-x64/publish'
artifact: linux-musl-x64-tests
displayName: Publish linux-musl-x64 Test Package
- publish: '$(testsFolder)/net6.0/freebsd-x64/publish'
artifact: freebsd-x64-tests
displayName: Publish freebsd-x64 Test Package
- publish: '$(testsFolder)/net6.0/osx-x64/publish'
artifact: osx-x64-tests
displayName: Publish osx-x64 Test Package
- stage: Build_Backend_Other
displayName: Build Backend (Other OS)
dependsOn: []
jobs:
- job: Backend
strategy:
@@ -81,10 +122,6 @@ stages:
osName: 'Mac'
imageName: ${{ variables.macImage }}
enableAnalysis: 'false'
Windows:
osName: 'Windows'
imageName: ${{ variables.windowsImage }}
enableAnalysis: 'false'
pool:
vmImage: $(imageName)
@@ -100,17 +137,22 @@ stages:
inputs:
version: $(dotnetVersion)
- bash: |
BUNDLEDVERSIONS=${AGENT_TOOLSDIRECTORY}/dotnet/sdk/${DOTNETVERSION}/Microsoft.NETCoreSdk.BundledVersions.props
echo $BUNDLEDVERSIONS
if grep -q freebsd-x64 $BUNDLEDVERSIONS; then
echo "Extra platforms already enabled"
else
echo "Enabling extra platform support"
SDK_PATH="${AGENT_TOOLSDIRECTORY}/dotnet/sdk/${DOTNETVERSION}"
BUNDLEDVERSIONS="${SDK_PATH}/Microsoft.NETCoreSdk.BundledVersions.props"
if ! grep -q freebsd-x64 $BUNDLEDVERSIONS; then
sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64;linux-x86/' $BUNDLEDVERSIONS
fi
displayName: Enable Extra Platform Support
displayName: Extra Platform Support
- task: Cache@2
inputs:
key: 'nuget | "$(Agent.OS)" | $(Build.SourcesDirectory)/src/Directory.Packages.props'
path: $(nugetCacheFolder)
displayName: Cache NuGet packages
- bash: ./build.sh --backend --enable-extra-platforms
displayName: Build Readarr Backend
env:
NUGET_PACKAGES: $(nugetCacheFolder)
- bash: |
find ${OUTPUTFOLDER} -type f ! -path "*/publish/*" -exec rm -rf {} \;
find ${OUTPUTFOLDER} -depth -empty -type d -exec rm -r "{}" \;
@@ -118,38 +160,10 @@ stages:
find ${TESTSFOLDER} -depth -empty -type d -exec rm -r "{}" \;
displayName: Clean up intermediate output
condition: and(succeeded(), ne(variables['osName'], 'Windows'))
- publish: $(outputFolder)
artifact: '$(osName)Backend'
displayName: Publish Backend
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/net6.0/win-x64/publish'
artifact: win-x64-tests
displayName: Publish win-x64 Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/net6.0/linux-x64/publish'
artifact: linux-x64-tests
displayName: Publish linux-x64 Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/net6.0/linux-x86/publish'
artifact: linux-x86-tests
displayName: Publish linux-x86 Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/net6.0/linux-musl-x64/publish'
artifact: linux-musl-x64-tests
displayName: Publish linux-musl-x64 Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/net6.0/freebsd-x64/publish'
artifact: freebsd-x64-tests
displayName: Publish freebsd-x64 Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/net6.0/osx-x64/publish'
artifact: osx-x64-tests
displayName: Publish osx-x64 Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- stage: Build_Frontend
displayName: Frontend
dependsOn: Setup
dependsOn: []
jobs:
- job: Build
strategy:
@@ -178,6 +192,7 @@ stages:
key: 'yarn | "$(osName)" | yarn.lock'
restoreKeys: |
yarn | "$(osName)"
yarn
path: $(yarnCacheFolder)
displayName: Cache Yarn packages
- bash: ./build.sh --frontend
@@ -189,10 +204,10 @@ stages:
artifact: '$(osName)Frontend'
displayName: Publish Frontend
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- stage: Installer
dependsOn:
- Build_Backend
- Build_Backend_Windows
- Build_Frontend
jobs:
- job: Windows_Installer
@@ -216,8 +231,8 @@ stages:
displayName: Fetch Frontend
- bash: |
./build.sh --packages --installer
cp distribution/windows/setup/output/Readarr.*win-x64.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Readarr.${BUILDNAME}.windows-core-x64-installer.exe
cp distribution/windows/setup/output/Readarr.*win-x86.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Readarr.${BUILDNAME}.windows-core-x86-installer.exe
cp setup/output/Readarr.*win-x64.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Readarr.${BUILDNAME}.windows-core-x64-installer.exe
cp setup/output/Readarr.*win-x86.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Readarr.${BUILDNAME}.windows-core-x86-installer.exe
displayName: Create Installers
- publish: $(Build.ArtifactStagingDirectory)
artifact: 'WindowsInstaller'
@@ -225,7 +240,7 @@ stages:
- stage: Packages
dependsOn:
- Build_Backend
- Build_Backend_Windows
- Build_Frontend
jobs:
- job: Other_Packages
@@ -391,29 +406,14 @@ stages:
SENTRY_AUTH_TOKEN: $(sentryAuthTokenServarr)
SENTRY_ORG: $(sentryOrg)
SENTRY_URL: $(sentryUrl)
- stage: Unit_Test
displayName: Unit Tests
dependsOn: Build_Backend
dependsOn: Build_Backend_Windows
condition: succeeded()
jobs:
- job: Prepare
pool:
vmImage: ${{ variables.linuxImage }}
steps:
- checkout: none
- task: DownloadPipelineArtifact@2
inputs:
buildType: 'current'
artifactName: 'not_backend_update'
targetPath: '.'
- bash: echo "##vso[task.setvariable variable=backendNotUpdated;isOutput=true]$(cat not_backend_update)"
name: setVar
- job: Unit
displayName: Unit Native
dependsOn: Prepare
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
workspace:
clean: all
@@ -479,8 +479,6 @@ stages:
- job: Unit_Docker
displayName: Unit Docker
dependsOn: Prepare
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
strategy:
matrix:
alpine:
@@ -494,11 +492,11 @@ stages:
pool:
vmImage: ${{ variables.linuxImage }}
container: $[ variables['containerImage'] ]
timeoutInMinutes: 10
steps:
- task: UseDotNet@2
displayName: 'Install .NET'
@@ -532,14 +530,12 @@ stages:
testResultsFiles: '**/TestResult.xml'
testRunTitle: '$(testName) Unit Tests'
failTaskOnFailedTests: true
- job: Unit_LinuxCore_Postgres14
displayName: Unit Native LinuxCore with Postgres14 Database
dependsOn: Prepare
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
- job: Unit_LinuxCore_Postgres
displayName: Unit Native LinuxCore with Postgres Database
variables:
pattern: 'Readarr.*.linux-core-x64.tar.gz'
artifactName: linux-x64-tests
artifactName: LinuxCoreTests
Readarr__Postgres__Host: 'localhost'
Readarr__Postgres__Port: '5432'
Readarr__Postgres__User: 'readarr'
@@ -549,7 +545,7 @@ stages:
vmImage: ${{ variables.linuxImage }}
timeoutInMinutes: 10
steps:
- task: UseDotNet@2
displayName: 'Install .net core'
@@ -560,7 +556,7 @@ stages:
displayName: Download Test Artifact
inputs:
buildType: 'current'
artifactName: $(artifactName)
artifactName: 'linux-x64-Tests'
targetPath: $(testsFolder)
- bash: find ${TESTSFOLDER} -name "Readarr.Test.Dummy" -exec chmod a+x {} \;
displayName: Make Test Dummy Executable
@@ -583,84 +579,15 @@ stages:
inputs:
testResultsFormat: 'NUnit'
testResultsFiles: '**/TestResult.xml'
testRunTitle: 'LinuxCore Postgres14 Unit Tests'
failTaskOnFailedTests: true
- job: Unit_LinuxCore_Postgres15
displayName: Unit Native LinuxCore with Postgres15 Database
dependsOn: Prepare
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
variables:
pattern: 'Readarr.*.linux-core-x64.tar.gz'
artifactName: linux-x64-tests
Readarr__Postgres__Host: 'localhost'
Readarr__Postgres__Port: '5432'
Readarr__Postgres__User: 'readarr'
Readarr__Postgres__Password: 'readarr'
pool:
vmImage: ${{ variables.linuxImage }}
timeoutInMinutes: 10
steps:
- task: UseDotNet@2
displayName: 'Install .net core'
inputs:
version: $(dotnetVersion)
- checkout: none
- task: DownloadPipelineArtifact@2
displayName: Download Test Artifact
inputs:
buildType: 'current'
artifactName: $(artifactName)
targetPath: $(testsFolder)
- bash: find ${TESTSFOLDER} -name "Readarr.Test.Dummy" -exec chmod a+x {} \;
displayName: Make Test Dummy Executable
condition: and(succeeded(), ne(variables['osName'], 'Windows'))
- bash: |
docker run -d --name=postgres15 \
-e POSTGRES_PASSWORD=readarr \
-e POSTGRES_USER=readarr \
-p 5432:5432/tcp \
-v /usr/share/zoneinfo/America/Chicago:/etc/localtime:ro \
postgres:15
displayName: Start postgres
- bash: |
chmod a+x ${TESTSFOLDER}/test.sh
ls -lR ${TESTSFOLDER}
${TESTSFOLDER}/test.sh Linux Unit Test
displayName: Run Tests
- task: PublishTestResults@2
displayName: Publish Test Results
inputs:
testResultsFormat: 'NUnit'
testResultsFiles: '**/TestResult.xml'
testRunTitle: 'LinuxCore Postgres15 Unit Tests'
testRunTitle: 'LinuxCore Postgres Unit Tests'
failTaskOnFailedTests: true
- stage: Integration
displayName: Integration
dependsOn: Packages
jobs:
- job: Prepare
pool:
vmImage: ${{ variables.linuxImage }}
steps:
- checkout: none
- task: DownloadPipelineArtifact@2
inputs:
buildType: 'current'
artifactName: 'not_backend_update'
targetPath: '.'
- bash: echo "##vso[task.setvariable variable=backendNotUpdated;isOutput=true]$(cat not_backend_update)"
name: setVar
- job: Integration_Native
displayName: Integration Native
dependsOn: Prepare
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
strategy:
matrix:
MacCore:
@@ -681,7 +608,7 @@ stages:
pool:
vmImage: $(imageName)
steps:
- task: UseDotNet@2
displayName: 'Install .net core'
@@ -703,7 +630,7 @@ stages:
targetPath: $(Build.ArtifactStagingDirectory)
- task: ExtractFiles@1
inputs:
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)'
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)'
destinationFolder: '$(Build.ArtifactStagingDirectory)/bin'
displayName: Extract Package
- bash: |
@@ -722,10 +649,8 @@ stages:
failTaskOnFailedTests: true
displayName: Publish Test Results
- job: Integration_LinuxCore_Postgres14
displayName: Integration Native LinuxCore with Postgres14 Database
dependsOn: Prepare
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
- job: Integration_LinuxCore_Postgres
displayName: Integration Native LinuxCore with Postgres Database
variables:
pattern: 'Readarr.*.linux-core-x64.tar.gz'
Readarr__Postgres__Host: 'localhost'
@@ -757,7 +682,7 @@ stages:
targetPath: $(Build.ArtifactStagingDirectory)
- task: ExtractFiles@1
inputs:
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)'
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)'
destinationFolder: '$(Build.ArtifactStagingDirectory)/bin'
displayName: Extract Package
- bash: |
@@ -780,77 +705,12 @@ stages:
inputs:
testResultsFormat: 'NUnit'
testResultsFiles: '**/TestResult.xml'
testRunTitle: 'Integration LinuxCore Postgres14 Database Integration Tests'
failTaskOnFailedTests: true
displayName: Publish Test Results
- job: Integration_LinuxCore_Postgres15
displayName: Integration Native LinuxCore with Postgres Database
dependsOn: Prepare
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
variables:
pattern: 'Readarr.*.linux-core-x64.tar.gz'
Readarr__Postgres__Host: 'localhost'
Readarr__Postgres__Port: '5432'
Readarr__Postgres__User: 'readarr'
Readarr__Postgres__Password: 'readarr'
pool:
vmImage: ${{ variables.linuxImage }}
steps:
- task: UseDotNet@2
displayName: 'Install .net core'
inputs:
version: $(dotnetVersion)
- checkout: none
- task: DownloadPipelineArtifact@2
displayName: Download Test Artifact
inputs:
buildType: 'current'
artifactName: 'linux-x64-tests'
targetPath: $(testsFolder)
- task: DownloadPipelineArtifact@2
displayName: Download Build Artifact
inputs:
buildType: 'current'
artifactName: Packages
itemPattern: '**/$(pattern)'
targetPath: $(Build.ArtifactStagingDirectory)
- task: ExtractFiles@1
inputs:
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)'
destinationFolder: '$(Build.ArtifactStagingDirectory)/bin'
displayName: Extract Package
- bash: |
mkdir -p ./bin/
cp -r -v ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin/Readarr/. ./bin/
displayName: Move Package Contents
- bash: |
docker run -d --name=postgres15 \
-e POSTGRES_PASSWORD=readarr \
-e POSTGRES_USER=readarr \
-p 5432:5432/tcp \
-v /usr/share/zoneinfo/America/Chicago:/etc/localtime:ro \
postgres:15
displayName: Start postgres
- bash: |
chmod a+x ${TESTSFOLDER}/test.sh
${TESTSFOLDER}/test.sh Linux Integration Test
displayName: Run Integration Tests
- task: PublishTestResults@2
inputs:
testResultsFormat: 'NUnit'
testResultsFiles: '**/TestResult.xml'
testRunTitle: 'Integration LinuxCore Postgres15 Database Integration Tests'
testRunTitle: 'Integration LinuxCore Postgres Database Integration Tests'
failTaskOnFailedTests: true
displayName: Publish Test Results
- job: Integration_FreeBSD
displayName: Integration Native FreeBSD
dependsOn: Prepare
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
workspace:
clean: all
variables:
@@ -895,8 +755,6 @@ stages:
- job: Integration_Docker
displayName: Integration Docker
dependsOn: Prepare
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
strategy:
matrix:
alpine:
@@ -915,7 +773,7 @@ stages:
container: $[ variables['containerImage'] ]
timeoutInMinutes: 15
steps:
- task: UseDotNet@2
displayName: 'Install .NET'
@@ -943,7 +801,7 @@ stages:
targetPath: $(Build.ArtifactStagingDirectory)
- task: ExtractFiles@1
inputs:
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)'
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)'
destinationFolder: '$(Build.ArtifactStagingDirectory)/bin'
displayName: Extract Package
- bash: |
@@ -965,7 +823,7 @@ stages:
- stage: Automation
displayName: Automation
dependsOn: Packages
jobs:
- job: Automation
strategy:
@@ -975,23 +833,20 @@ stages:
artifactName: 'linux-x64'
imageName: ${{ variables.linuxImage }}
pattern: 'Readarr.*.linux-core-x64.tar.gz'
failBuild: true
Mac:
osName: 'Mac'
artifactName: 'osx-x64'
imageName: ${{ variables.macImage }}
pattern: 'Readarr.*.osx-core-x64.tar.gz'
failBuild: true
Windows:
osName: 'Windows'
artifactName: 'win-x64'
imageName: ${{ variables.windowsImage }}
pattern: 'Readarr.*.windows-core-x64.zip'
failBuild: true
pool:
vmImage: $(imageName)
steps:
- task: UseDotNet@2
displayName: 'Install .net core'
@@ -1013,7 +868,7 @@ stages:
targetPath: $(Build.ArtifactStagingDirectory)
- task: ExtractFiles@1
inputs:
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)'
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)'
destinationFolder: '$(Build.ArtifactStagingDirectory)/bin'
displayName: Extract Package
- bash: |
@@ -1033,35 +888,20 @@ stages:
TargetFolder: '$(Build.ArtifactStagingDirectory)/screenshots'
- publish: $(Build.ArtifactStagingDirectory)/screenshots
artifact: '$(osName)AutomationScreenshots'
displayName: Publish Screenshot Bundle
condition: and(succeeded(), eq(variables['System.JobAttempt'], '1'))
displayName: Publish Screenshot Bundle
- task: PublishTestResults@2
inputs:
testResultsFormat: 'NUnit'
testResultsFiles: '**/TestResult.xml'
testRunTitle: '$(osName) Automation Tests'
failTaskOnFailedTests: $(failBuild)
failTaskOnFailedTests: true
displayName: Publish Test Results
- stage: Analyze
dependsOn:
- Setup
dependsOn: []
displayName: Analyze
jobs:
- job: Prepare
pool:
vmImage: ${{ variables.linuxImage }}
steps:
- checkout: none
- task: DownloadPipelineArtifact@2
inputs:
buildType: 'current'
artifactName: 'not_backend_update'
targetPath: '.'
- bash: echo "##vso[task.setvariable variable=backendNotUpdated;isOutput=true]$(cat not_backend_update)"
name: setVar
- job: Lint_Frontend
displayName: Lint Frontend
strategy:
@@ -1087,6 +927,7 @@ stages:
key: 'yarn | "$(osName)" | yarn.lock'
restoreKeys: |
yarn | "$(osName)"
yarn
path: $(yarnCacheFolder)
displayName: Cache Yarn packages
- bash: ./build.sh --lint
@@ -1115,16 +956,11 @@ stages:
cliProjectVersion: '$(readarrVersion)'
cliSources: './frontend'
- task: SonarCloudAnalyze@1
- job: Api_Docs
displayName: API Docs
dependsOn: Prepare
condition: |
and
(
and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/develop')),
and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
)
and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/develop'))
pool:
vmImage: ${{ variables.windowsImage }}
@@ -1137,7 +973,7 @@ stages:
- checkout: self
submodules: true
persistCredentials: true
fetchDepth: 1
fetchDepth: 1
- bash: ./docs.sh Windows
displayName: Create openapi.json
- bash: |
@@ -1145,9 +981,10 @@ stages:
git config --global user.name "Servarr"
git checkout -b api-docs
git add .
if git status | grep -q modified
git status
if git status | grep modified
then
git commit -am 'Automated API Docs update'
git commit -am 'Automated API Docs update [skip ci]'
git push -f --set-upstream origin api-docs
curl -X POST -H "Authorization: token ${GITHUBTOKEN}" -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/readarr/readarr/pulls -d '{"head":"api-docs","base":"develop","title":"Update API docs"}'
else
@@ -1171,25 +1008,33 @@ stages:
- job: Analyze_Backend
displayName: Backend
dependsOn: Prepare
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
variables:
disable.coverage.autogenerate: 'true'
EnableAnalyzers: 'false'
pool:
vmImage: ${{ variables.windowsImage }}
vmImage: ${{ variables.linuxImage }}
steps:
- task: UseDotNet@2
displayName: 'Install .net core'
displayName: 'Install .net core 2.1'
inputs:
version: 2.1.815
- task: UseDotNet@2
displayName: 'Install .net core 3.1'
inputs:
version: 3.1.413
- task: UseDotNet@2
displayName: 'Install .net core 5.0'
inputs:
version: $(dotnetVersion)
- checkout: self # Need history for Sonar analysis
submodules: true
- powershell: Set-Service SCardSvr -StartupType Manual
displayName: Enable Windows Test Service
- task: Cache@2
inputs:
key: 'nuget | "$(Agent.OS)" | $(Build.SourcesDirectory)/src/Directory.Packages.props'
path: $(nugetCacheFolder)
displayName: Cache NuGet packages
- task: SonarCloudPrepare@1
condition: eq(variables['System.PullRequest.IsFork'], 'False')
inputs:
@@ -1200,14 +1045,16 @@ stages:
projectName: 'Readarr'
projectVersion: '$(readarrVersion)'
extraProperties: |
sonar.exclusions=**/obj/**,**/*.dll,**/NzbDrone.Core.Test/Files/**/*,./frontend/**,**/ExternalModules/**,./src/Libraries/**
sonar.exclusions=**/obj/**,**/*.dll,**/NzbDrone.Core.Test/Files/**/*,./frontend/**,./src/Libraries/**
sonar.coverage.exclusions=**/Readarr.Api.V1/**/*
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 net6.0 -r linux-x64
TEST_DIR=_tests/net6.0/linux-x64/publish/ ./test.sh Linux Unit Coverage
displayName: Coverage Unit Tests
env:
NUGET_PACKAGES: $(nugetCacheFolder)
- task: SonarCloudAnalyze@1
condition: eq(variables['System.PullRequest.IsFork'], 'False')
displayName: Publish SonarCloud Results
@@ -1230,6 +1077,7 @@ stages:
- Unit_Test
- Integration
- Automation
- Build_Backend_Other
condition: eq(variables['system.pullrequest.isfork'], false)
displayName: Build Status Report
jobs:
@@ -1253,4 +1101,3 @@ stages:
DISCORDCHANNELID: $(discordChannelId)
DISCORDWEBHOOKKEY: $(discordWebhookKey)
DISCORDTHREADID: $(discordThreadId)

View File

@@ -23,7 +23,7 @@ UpdateVersionNumber()
echo "Updating Version Info"
sed -i'' -e "s/<AssemblyVersion>[0-9.*]\+<\/AssemblyVersion>/<AssemblyVersion>$READARRVERSION<\/AssemblyVersion>/g" src/Directory.Build.props
sed -i'' -e "s/<AssemblyConfiguration>[\$()A-Za-z-]\+<\/AssemblyConfiguration>/<AssemblyConfiguration>${BUILD_SOURCEBRANCHNAME}<\/AssemblyConfiguration>/g" src/Directory.Build.props
sed -i'' -e "s/<string>10.0.0.0<\/string>/<string>$READARRVERSION<\/string>/g" distribution/osx/Readarr.app/Contents/Info.plist
sed -i'' -e "s/<string>10.0.0.0<\/string>/<string>$READARRVERSION<\/string>/g" macOS/Readarr.app/Contents/Info.plist
fi
}
@@ -183,7 +183,7 @@ PackageMacOSApp()
rm -rf $folder
mkdir -p $folder
cp -r distribution/osx/Readarr.app $folder
cp -r macOS/Readarr.app $folder
mkdir -p $folder/Readarr.app/Contents/MacOS
echo "Copying Binaries"
@@ -245,7 +245,7 @@ BuildInstaller()
local framework="$1"
local runtime="$2"
./_inno/ISCC.exe distribution/windows/setup/readarr.iss "//DFramework=$framework" "//DRuntime=$runtime"
./_inno/ISCC.exe setup/readarr.iss "//DFramework=$framework" "//DRuntime=$runtime"
}
InstallInno()

View File

@@ -108,7 +108,7 @@ class RemoveQueueItemModal extends Component {
type={inputTypes.CHECK}
name="remove"
value={remove}
helpTextWarning={translate('RemoveHelpTextWarning')}
helpTextWarning={translate('RemoveFromDownloadClientHelpTextWarning')}
isDisabled={!canIgnore}
onChange={this.onRemoveChange}
/>

View File

@@ -1,7 +1,6 @@
.version {
margin: 0 3px;
font-weight: bold;
font-family: var(--defaultFontFamily);
}
.maintenance {

View File

@@ -2,7 +2,6 @@ import PropTypes from 'prop-types';
import React from 'react';
import Button from 'Components/Link/Button';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
@@ -65,12 +64,12 @@ function AppUpdatedModalContent(props) {
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{translate('AppUpdated', { appName: 'Readarr' })}
Readarr Updated
</ModalHeader>
<ModalBody>
<div>
<InlineMarkdown data={translate('AppUpdatedVersion', { appName: 'Readarr', version })} blockClassName={styles.version} />
Version <span className={styles.version}>{version}</span> of Readarr has been installed, in order to get the latest changes you'll need to reload Readarr.
</div>
{
@@ -78,14 +77,16 @@ function AppUpdatedModalContent(props) {
<div>
{
!update.changes &&
<div className={styles.maintenance}>{translate('MaintenanceRelease')}</div>
<div className={styles.maintenance}>
{translate('MaintenanceRelease')}
</div>
}
{
!!update.changes &&
<div>
<div className={styles.changes}>
{translate('WhatsNew')}
What's new?
</div>
<UpdateChanges
@@ -112,14 +113,14 @@ function AppUpdatedModalContent(props) {
<Button
onPress={onSeeChangesPress}
>
{translate('RecentChanges')}
Recent Changes
</Button>
<Button
kind={kinds.PRIMARY}
onPress={onModalClose}
>
{translate('Reload')}
Reload
</Button>
</ModalFooter>
</ModalContent>

View File

@@ -7,7 +7,6 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './ConnectionLostModal.css';
function ConnectionLostModal(props) {
@@ -23,16 +22,16 @@ function ConnectionLostModal(props) {
>
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{translate('ConnectionLost')}
Connection Lost
</ModalHeader>
<ModalBody>
<div>
{translate('ConnectionLostToBackend', { appName: 'Readarr' })}
Readarr has lost its connection to the backend and will need to be reloaded to restore functionality.
</div>
<div className={styles.automatic}>
{translate('ConnectionLostReconnect', { appName: 'Readarr' })}
Readarr will try to connect automatically, or you can click reload below.
</div>
</ModalBody>
<ModalFooter>
@@ -40,7 +39,7 @@ function ConnectionLostModal(props) {
kind={kinds.PRIMARY}
onPress={onModalClose}
>
{translate('Reload')}
Reload
</Button>
</ModalFooter>
</ModalContent>

View File

@@ -143,7 +143,7 @@ class BookshelfFooter extends Component {
<div>
<div className={styles.label}>
{translate('CountAuthorsSelected', { selectedCount })}
{selectedCount} Author(s) Selected
</div>
<SpinnerButton

View File

@@ -41,7 +41,7 @@ class NumberInput extends Component {
componentDidUpdate(prevProps, prevState) {
const { value } = this.props;
if (!isNaN(value) && value !== prevProps.value && !this.state.isFocused) {
if (value !== prevProps.value && !this.state.isFocused) {
this.setState({
value: value == null ? '' : value.toString()
});

View File

@@ -97,7 +97,6 @@ class SpinnerErrorButton extends Component {
render() {
const {
kind,
isSpinning,
error,
children,
@@ -113,7 +112,7 @@ class SpinnerErrorButton extends Component {
const showIcon = wasSuccessful || hasWarning || hasError;
let iconName = icons.CHECK;
let iconKind = kind === kinds.PRIMARY ? kinds.DEFAULT : kinds.SUCCESS;
let iconKind = kinds.SUCCESS;
if (hasWarning) {
iconName = icons.WARNING;
@@ -127,7 +126,6 @@ class SpinnerErrorButton extends Component {
return (
<SpinnerButton
kind={kind}
isSpinning={isSpinning}
{...otherProps}
>
@@ -156,7 +154,6 @@ class SpinnerErrorButton extends Component {
}
SpinnerErrorButton.propTypes = {
kind: PropTypes.oneOf(kinds.all),
isSpinning: PropTypes.bool.isRequired,
error: PropTypes.object,
children: PropTypes.node.isRequired

View File

@@ -10,8 +10,7 @@ class InlineMarkdown extends Component {
render() {
const {
className,
data,
blockClassName
data
} = this.props;
// For now only replace links or code blocks (not both)
@@ -48,7 +47,7 @@ class InlineMarkdown extends Component {
markdownBlocks.push(data.substr(endIndex, match.index - endIndex));
}
markdownBlocks.push(<code key={`code-${match.index}`} className={blockClassName ?? null}>{match[0].substring(1, match[0].length - 1)}</code>);
markdownBlocks.push(<code key={`code-${match.index}`}>{match[0].substring(1, match[0].length - 1)}</code>);
endIndex = match.index + match[0].length;
}
@@ -67,8 +66,7 @@ class InlineMarkdown extends Component {
InlineMarkdown.propTypes = {
className: PropTypes.string,
data: PropTypes.string,
blockClassName: PropTypes.string
data: PropTypes.string
};
export default InlineMarkdown;

View File

@@ -6,7 +6,6 @@ export const BOOKSHELF = 'bookshelf';
export const KEY_VALUE_LIST = 'keyValueList';
export const MONITOR_BOOKS_SELECT = 'monitorBooksSelect';
export const MONITOR_NEW_ITEMS_SELECT = 'monitorNewItemsSelect';
export const FLOAT = 'float';
export const NUMBER = 'number';
export const OAUTH = 'oauth';
export const PASSWORD = 'password';
@@ -35,7 +34,6 @@ export const all = [
KEY_VALUE_LIST,
MONITOR_BOOKS_SELECT,
MONITOR_NEW_ITEMS_SELECT,
FLOAT,
NUMBER,
OAUTH,
PASSWORD,

View File

@@ -1,11 +1,10 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
import Icon from 'Components/Icon';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { icons, kinds, sortDirections } from 'Helpers/Props';
import { icons, sortDirections } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import InteractiveSearchRow from './InteractiveSearchRow';
import styles from './InteractiveSearch.css';
@@ -113,17 +112,17 @@ function InteractiveSearch(props) {
{
!isFetching && isPopulated && !totalReleasesCount ?
<Alert kind={kinds.INFO}>
{translate('NoResultsFound')}
</Alert> :
<div className={styles.blankpad}>
No results found
</div> :
null
}
{
!!totalReleasesCount && isPopulated && !items.length ?
<Alert kind={kinds.WARNING}>
{translate('AllResultsAreHiddenByTheAppliedFilter')}
</Alert> :
<div className={styles.blankpad}>
All results are hidden by the applied filter
</div> :
null
}
@@ -158,7 +157,7 @@ function InteractiveSearch(props) {
{
totalReleasesCount !== items.length && !!items.length ?
<div className={styles.filteredMessage}>
{translate('SomeResultsAreHiddenByTheAppliedFilter')}
Some results are hidden by the applied filter
</div> :
null
}

View File

@@ -152,7 +152,7 @@ class CustomFormat extends Component {
isOpen={this.state.isDeleteCustomFormatModalOpen}
kind={kinds.DANGER}
title={translate('DeleteCustomFormat')}
message={translate('DeleteCustomFormatMessageText', { name })}
message={translate('DeleteCustomFormatMessageText', [name])}
confirmLabel={translate('Delete')}
isSpinning={isDeleting}
onConfirm={this.onConfirmDeleteCustomFormat}

View File

@@ -115,7 +115,7 @@ class Specification extends Component {
isOpen={this.state.isDeleteSpecificationModalOpen}
kind={kinds.DANGER}
title={translate('DeleteCondition')}
message={translate('DeleteConditionMessageText', { name })}
message={translate('DeleteConditionMessageText', [name])}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteSpecification}
onCancel={this.onDeleteSpecificationModalClose}

View File

@@ -113,7 +113,7 @@ class DownloadClient extends Component {
isOpen={this.state.isDeleteDownloadClientModalOpen}
kind={kinds.DANGER}
title={translate('DeleteDownloadClient')}
message={translate('DeleteDownloadClientMessageText', { name })}
message={translate('DeleteDownloadClientMessageText', [name])}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteDownloadClient}
onCancel={this.onDeleteDownloadClientModalClose}

View File

@@ -180,7 +180,7 @@ function ManageDownloadClientsEditModalContent(
<ModalFooter className={styles.modalFooter}>
<div className={styles.selected}>
{translate('CountDownloadClientsSelected', { selectedCount })}
{translate('CountDownloadClientsSelected', [selectedCount])}
</div>
<div>

View File

@@ -286,9 +286,9 @@ function ManageDownloadClientsModalContent(
isOpen={isDeleteModalOpen}
kind={kinds.DANGER}
title={translate('DeleteSelectedDownloadClients')}
message={translate('DeleteSelectedDownloadClientsMessageText', {
count: selectedIds.length,
})}
message={translate('DeleteSelectedDownloadClientsMessageText', [
selectedIds.length,
])}
confirmLabel={translate('Delete')}
onConfirm={onConfirmDelete}
onCancel={onDeleteModalClose}

View File

@@ -1,12 +1,10 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Icon from 'Components/Icon';
import Link from 'Components/Link/Link';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import PageSectionContent from 'Components/Page/PageSectionContent';
import { icons, kinds } from 'Helpers/Props';
import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditRemotePathMappingModalConnector from './EditRemotePathMappingModalConnector';
import RemotePathMapping from './RemotePathMapping';
@@ -52,11 +50,6 @@ class RemotePathMappings extends Component {
errorMessage={translate('UnableToLoadRemotePathMappings')}
{...otherProps}
>
<Alert kind={kinds.INFO}>
<InlineMarkdown data={translate('RemotePathMappingsInfo', { app: 'Readarr', wikiLink: 'https://wiki.servarr.com/readarr/settings#remote-path-mappings' })} />
</Alert>
<div className={styles.remotePathMappingsHeader}>
<div className={styles.host}>
{translate('Host')}

View File

@@ -103,6 +103,7 @@ class GeneralSettings extends Component {
isResettingApiKey,
isWindows,
isWindowsService,
isDocker,
mode,
packageUpdateMechanism,
onInputChange,
@@ -170,6 +171,7 @@ class GeneralSettings extends Component {
settings={settings}
isWindows={isWindows}
packageUpdateMechanism={packageUpdateMechanism}
isDocker={isDocker}
onInputChange={onInputChange}
/>
@@ -212,6 +214,7 @@ GeneralSettings.propTypes = {
hasSettings: PropTypes.bool.isRequired,
isWindows: PropTypes.bool.isRequired,
isWindowsService: PropTypes.bool.isRequired,
isDocker: PropTypes.bool.isRequired,
mode: PropTypes.string.isRequired,
packageUpdateMechanism: PropTypes.string.isRequired,
onInputChange: PropTypes.func.isRequired,

View File

@@ -26,6 +26,7 @@ function createMapStateToProps() {
isResettingApiKey,
isWindows: systemStatus.isWindows,
isWindowsService: systemStatus.isWindows && systemStatus.mode === 'service',
isDocker: systemStatus.isDocker,
mode: systemStatus.mode,
packageUpdateMechanism: systemStatus.packageUpdateMechanism,
...sectionSettings

View File

@@ -8,17 +8,12 @@ import { inputTypes, sizes } from 'Helpers/Props';
import titleCase from 'Utilities/String/titleCase';
import translate from 'Utilities/String/translate';
const branchValues = [
'master',
'develop',
'nightly'
];
function UpdateSettings(props) {
const {
advancedSettings,
settings,
isWindows,
isDocker,
packageUpdateMechanism,
onInputChange
} = props;
@@ -49,21 +44,32 @@ function UpdateSettings(props) {
updateOptions.push({ key: 'script', value: 'Script' });
if (isDocker) {
return (
<FieldSet legend={translate('Updates')}>
<div>
{translate('UpdatingIsDisabledInsideADockerContainerUpdateTheContainerImageInstead')}
</div>
</FieldSet>
);
}
return (
<FieldSet legend={translate('Updates')}>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('Branch')}</FormLabel>
<FormLabel>
{translate('Branch')}
</FormLabel>
<FormInputGroup
type={inputTypes.AUTO_COMPLETE}
type={inputTypes.TEXT}
name="branch"
helpText={usingExternalUpdateMechanism ? translate('UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism') : translate('UsingExternalUpdateMechanismBranchToUseToUpdateReadarr')}
helpLink="https://wiki.servarr.com/readarr/faq#how-do-I-update-my-readarr"
{...branch}
values={branchValues}
onChange={onInputChange}
readOnly={usingExternalUpdateMechanism}
/>
@@ -77,13 +83,14 @@ function UpdateSettings(props) {
isAdvanced={true}
size={sizes.MEDIUM}
>
<FormLabel>{translate('Automatic')}</FormLabel>
<FormLabel>
{translate('Automatic')}
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="updateAutomatically"
helpText={translate('UpdateAutomaticallyHelpText')}
helpTextWarning={updateMechanism.value === 'docker' ? translate('AutomaticUpdatesDisabledDocker', { appName: 'Readarr' }) : undefined}
onChange={onInputChange}
{...updateAutomatically}
/>
@@ -93,7 +100,9 @@ function UpdateSettings(props) {
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('Mechanism')}</FormLabel>
<FormLabel>
{translate('Mechanism')}
</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
@@ -112,7 +121,9 @@ function UpdateSettings(props) {
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('ScriptPath')}</FormLabel>
<FormLabel>
{translate('ScriptPath')}
</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
@@ -133,6 +144,7 @@ UpdateSettings.propTypes = {
advancedSettings: PropTypes.bool.isRequired,
settings: PropTypes.object.isRequired,
isWindows: PropTypes.bool.isRequired,
isDocker: PropTypes.bool.isRequired,
packageUpdateMechanism: PropTypes.string.isRequired,
onInputChange: PropTypes.func.isRequired
};

View File

@@ -107,7 +107,7 @@ class ImportList extends Component {
isOpen={this.state.isDeleteImportListModalOpen}
kind={kinds.DANGER}
title={translate('DeleteImportList')}
message={translate('DeleteImportListMessageText', { name })}
message={translate('DeleteImportListMessageText', [name])}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteImportList}
onCancel={this.onDeleteImportListModalClose}

View File

@@ -184,7 +184,7 @@ function ManageImportListsEditModalContent(
<ModalFooter className={styles.modalFooter}>
<div className={styles.selected}>
{translate('CountImportListsSelected', { selectedCount })}
{translate('CountImportListsSelected', [selectedCount])}
</div>
<div>

View File

@@ -283,9 +283,9 @@ function ManageImportListsModalContent(
isOpen={isDeleteModalOpen}
kind={kinds.DANGER}
title={translate('DeleteSelectedImportLists')}
message={translate('DeleteSelectedImportListsMessageText', {
count: selectedIds.length,
})}
message={translate('DeleteSelectedImportListsMessageText', [
selectedIds.length,
])}
confirmLabel={translate('Delete')}
onConfirm={onConfirmDelete}
onCancel={onDeleteModalClose}

View File

@@ -152,7 +152,7 @@ class Indexer extends Component {
isOpen={this.state.isDeleteIndexerModalOpen}
kind={kinds.DANGER}
title={translate('DeleteIndexer')}
message={translate('DeleteIndexerMessageText', { name })}
message={translate('DeleteIndexerMessageText', [name])}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteIndexer}
onCancel={this.onDeleteIndexerModalClose}

View File

@@ -178,7 +178,7 @@ function ManageIndexersEditModalContent(
<ModalFooter className={styles.modalFooter}>
<div className={styles.selected}>
{translate('CountIndexersSelected', { selectedCount })}
{translate('CountIndexersSelected', [selectedCount])}
</div>
<div>

View File

@@ -281,9 +281,9 @@ function ManageIndexersModalContent(props: ManageIndexersModalContentProps) {
isOpen={isDeleteModalOpen}
kind={kinds.DANGER}
title={translate('DeleteSelectedIndexers')}
message={translate('DeleteSelectedIndexersMessageText', {
count: selectedIds.length,
})}
message={translate('DeleteSelectedIndexersMessageText', [
selectedIds.length,
])}
confirmLabel={translate('Delete')}
onConfirm={onConfirmDelete}
onCancel={onDeleteModalClose}

View File

@@ -95,7 +95,7 @@ class RootFolder extends Component {
isOpen={this.state.isDeleteRootFolderModalOpen}
kind={kinds.DANGER}
title={translate('DeleteRootFolder')}
message={translate('DeleteRootFolderMessageText', { name })}
message={translate('DeleteRootFolderMessageText', [name])}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteRootFolder}
onCancel={this.onDeleteRootFolderModalClose}

View File

@@ -227,7 +227,7 @@ class Notification extends Component {
isOpen={this.state.isDeleteNotificationModalOpen}
kind={kinds.DANGER}
title={translate('DeleteNotification')}
message={translate('DeleteNotificationMessageText', { name })}
message={translate('DeleteNotificationMessageText', [name])}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteNotification}
onCancel={this.onDeleteNotificationModalClose}

View File

@@ -144,7 +144,7 @@ class MetadataProfile extends Component {
isOpen={this.state.isDeleteMetadataProfileModalOpen}
kind={kinds.DANGER}
title={translate('DeleteMetadataProfile')}
message={translate('DeleteMetadataProfileMessageText', { name })}
message={translate('DeleteMetadataProfileMessageText', [name])}
confirmLabel={translate('Delete')}
isSpinning={isDeleting}
onConfirm={this.onConfirmDeleteMetadataProfile}

View File

@@ -162,7 +162,7 @@ class QualityProfile extends Component {
isOpen={this.state.isDeleteQualityProfileModalOpen}
kind={kinds.DANGER}
title={translate('DeleteQualityProfile')}
message={translate('DeleteQualityProfileMessageText', { name })}
message={translate('DeleteQualityProfileMessageText', [name])}
confirmLabel={translate('Delete')}
isSpinning={isDeleting}
onConfirm={this.onConfirmDeleteQualityProfile}

View File

@@ -4,8 +4,6 @@ import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHand
import createSaveProviderHandler, { createCancelSaveProviderHandler } from 'Store/Actions/Creators/createSaveProviderHandler';
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
import { createThunk } from 'Store/thunks';
import monitorNewItemsOptions from 'Utilities/Author/monitorNewItemsOptions';
import monitorOptions from 'Utilities/Author/monitorOptions';
//
// Variables
@@ -53,10 +51,6 @@ export default {
port: 8080,
useSsl: false,
outputProfile: 'default',
defaultQualityProfileId: 0,
defaultMetadataProfileId: 0,
defaultMonitorOption: monitorOptions[0].key,
defaultNewItemMonitorOption: monitorNewItemsOptions[0].key,
defaultTags: []
},
isSaving: false,

View File

@@ -138,7 +138,7 @@ class BackupRow extends Component {
isOpen={isConfirmDeleteModalOpen}
kind={kinds.DANGER}
title={translate('DeleteBackup')}
message={translate('DeleteBackupMessageText', { name })}
message={translate('DeleteBackupMessageText', [name])}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeletePress}
onCancel={this.onConfirmDeleteModalClose}

View File

@@ -146,7 +146,7 @@ class RestoreBackupModalContent extends Component {
<ModalBody>
{
!!id && translate('WouldYouLikeToRestoreBackup', { name })
!!id && `Would you like to restore the backup '${name}'?`
}
{

View File

@@ -39,14 +39,6 @@ function getInternalLink(source) {
to="/settings/downloadclients"
/>
);
case 'NotificationStatusCheck':
return (
<IconButton
name={icons.SETTINGS}
title={translate('Settings')}
to="/settings/connect"
/>
);
case 'RootFolderCheck':
return (
<IconButton

View File

@@ -25,19 +25,18 @@ export async function fetchTranslations(): Promise<boolean> {
export default function translate(
key: string,
tokens?: Record<string, string | number | boolean>
args?: (string | number | boolean)[]
) {
if (!(key in translations)) {
console.debug(key);
}
const translation = translations[key] || key;
if (tokens) {
// Fallback to the old behaviour for translations not yet updated to use named tokens
Object.values(tokens).forEach((value, index) => {
tokens[index] = value;
if (args) {
return translation.replace(/\{(\d+)\}/g, (match, index) => {
return String(args[index]) ?? match;
});
return translation.replace(/\{([a-z0-9]+?)\}/gi, (match, tokenMatch) =>
String(tokens[tokenMatch] ?? match)
);
}
return translation;

View File

@@ -44,16 +44,16 @@ Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopIcon"; Description: "{cm:CreateDesktopIcon}"
Name: "windowsService"; Description: "Install Windows Service (Starts when the computer starts as the LocalService user, you will need to change the user to access network shares)"; GroupDescription: "Start automatically"; Flags: exclusive
Name: "startupShortcut"; Description: "Create shortcut in Startup folder (Starts when you log into Windows)"; GroupDescription: "Start automatically"; Flags: exclusive unchecked
Name: "windowsService"; Description: "Install Windows Service (Starts when the computer starts as the LocalService user, you will need to change the user to access network shares)"; GroupDescription: "Start automatically"; Flags: exclusive unchecked
Name: "startupShortcut"; Description: "Create shortcut in Startup folder (Starts when you log into Windows)"; GroupDescription: "Start automatically"; Flags: exclusive
Name: "none"; Description: "Do not start automatically"; GroupDescription: "Start automatically"; Flags: exclusive unchecked
[Dirs]
Name: "{app}"; Permissions: users-modify
[Files]
Source: "..\..\..\_artifacts\{#Runtime}\{#Framework}\Readarr\Readarr.exe"; DestDir: "{app}\bin"; Flags: ignoreversion
Source: "..\..\..\_artifacts\{#Runtime}\{#Framework}\Readarr\*"; Excludes: "Readarr.Update"; DestDir: "{app}\bin"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "..\_artifacts\{#Runtime}\{#Framework}\Readarr\Readarr.exe"; DestDir: "{app}\bin"; Flags: ignoreversion
Source: "..\_artifacts\{#Runtime}\{#Framework}\Readarr\*"; Excludes: "Readarr.Update"; DestDir: "{app}\bin"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
@@ -72,13 +72,12 @@ Filename: "{app}\bin\Readarr.exe"; Description: "Open Readarr Web UI"; Flags: po
Filename: "{app}\bin\Readarr.exe"; Description: "Start Readarr"; Flags: postinstall skipifsilent nowait; Tasks: startupShortcut none;
[UninstallRun]
Filename: "{app}\bin\readarr.console.exe"; Parameters: "/u"; Flags: waituntilterminated skipifdoesntexist
Filename: "{app}\bin\Readarr.Console.exe"; Parameters: "/u"; Flags: waituntilterminated skipifdoesntexist
[Code]
function PrepareToInstall(var NeedsRestart: Boolean): String;
var
ResultCode: Integer;
begin
Exec('net', 'stop readarr', '', 0, ewWaitUntilTerminated, ResultCode)
Exec('sc', 'delete readarr', '', 0, ewWaitUntilTerminated, ResultCode)
Exec(ExpandConstant('{commonappdata}\Readarr\bin\Readarr.Console.exe'), '/u', '', 0, ewWaitUntilTerminated, ResultCode)
end;

View File

@@ -32,7 +32,7 @@
<PackageVersion Include="NLog.Extensions.Logging" Version="5.2.3" />
<PackageVersion Include="NLog" Version="5.1.4" />
<PackageVersion Include="NLog.Targets.Syslog" Version="7.0.0" />
<PackageVersion Include="Npgsql" Version="7.0.4" />
<PackageVersion Include="Npgsql" Version="6.0.9" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageVersion Include="NUnit" Version="3.13.3" />
<PackageVersion Include="NunitXml.TestLogger" Version="3.0.117" />

View File

@@ -40,10 +40,6 @@ namespace NzbDrone.Automation.Test.PageModel
var element = d.FindElement(By.ClassName("followingBalls"));
return !element.Displayed;
}
catch (StaleElementReferenceException)
{
return true;
}
catch (NoSuchElementException)
{
return true;

View File

@@ -838,7 +838,7 @@ namespace NzbDrone.Common.Test.DiskTests
// Note: never returns anything.
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.GetFileInfos(It.IsAny<string>(), It.IsAny<bool>()))
.Setup(v => v.GetFileInfos(It.IsAny<string>(), It.IsAny<SearchOption>()))
.Returns(new List<IFileInfo>());
Mocker.GetMock<IDiskProvider>()
@@ -878,8 +878,8 @@ namespace NzbDrone.Common.Test.DiskTests
.Returns<string>(v => fileSystem.DirectoryInfo.FromDirectoryName(v).GetDirectories().ToList());
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.GetFileInfos(It.IsAny<string>(), It.IsAny<bool>()))
.Returns((string v, bool recursive) => fileSystem.DirectoryInfo.FromDirectoryName(v).GetFiles("*", new EnumerationOptions { RecurseSubdirectories = recursive }).ToList());
.Setup(v => v.GetFileInfos(It.IsAny<string>(), It.IsAny<SearchOption>()))
.Returns((string v, SearchOption option) => fileSystem.DirectoryInfo.FromDirectoryName(v).GetFiles("*", option).ToList());
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.GetFileSize(It.IsAny<string>()))

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.GZip;
@@ -12,7 +11,7 @@ namespace NzbDrone.Common
public interface IArchiveService
{
void Extract(string compressedFile, string destination);
void CreateZip(string path, IEnumerable<string> files);
void CreateZip(string path, params string[] files);
}
public class ArchiveService : IArchiveService
@@ -40,7 +39,7 @@ namespace NzbDrone.Common
_logger.Debug("Extraction complete.");
}
public void CreateZip(string path, IEnumerable<string> files)
public void CreateZip(string path, params string[] files)
{
using (var zipFile = ZipFile.Create(path))
{

View File

@@ -53,7 +53,7 @@ namespace NzbDrone.Common.Disk
{
CheckFolderExists(path);
var dirFiles = GetFiles(path, true).ToList();
var dirFiles = GetFiles(path, SearchOption.AllDirectories).ToList();
if (!dirFiles.Any())
{
@@ -156,11 +156,11 @@ namespace NzbDrone.Common.Disk
return _fileSystem.Directory.EnumerateFileSystemEntries(path).Empty();
}
public IEnumerable<string> GetDirectories(string path)
public string[] GetDirectories(string path)
{
Ensure.That(path, () => path).IsValidPath(PathValidationType.CurrentOs);
return _fileSystem.Directory.EnumerateDirectories(path);
return _fileSystem.Directory.GetDirectories(path);
}
public string[] GetDirectories(string path, SearchOption searchOption)
@@ -170,22 +170,18 @@ namespace NzbDrone.Common.Disk
return _fileSystem.Directory.GetDirectories(path, "*", searchOption);
}
public IEnumerable<string> GetFiles(string path, bool recursive)
public string[] GetFiles(string path, SearchOption searchOption)
{
Ensure.That(path, () => path).IsValidPath(PathValidationType.CurrentOs);
return _fileSystem.Directory.EnumerateFiles(path, "*", new EnumerationOptions
{
RecurseSubdirectories = recursive,
IgnoreInaccessible = true
});
return _fileSystem.Directory.GetFiles(path, "*.*", searchOption);
}
public long GetFolderSize(string path)
{
Ensure.That(path, () => path).IsValidPath(PathValidationType.CurrentOs);
return GetFiles(path, true).Sum(e => _fileSystem.FileInfo.FromFileName(e).Length);
return GetFiles(path, SearchOption.AllDirectories).Sum(e => _fileSystem.FileInfo.FromFileName(e).Length);
}
public long GetFileSize(string path)
@@ -306,9 +302,8 @@ namespace NzbDrone.Common.Disk
{
Ensure.That(path, () => path).IsValidPath(PathValidationType.CurrentOs);
var files = GetFiles(path, recursive);
files.ToList().ForEach(RemoveReadOnly);
var files = _fileSystem.Directory.GetFiles(path, "*.*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
Array.ForEach(files, RemoveReadOnly);
_fileSystem.Directory.Delete(path, recursive);
}
@@ -409,7 +404,7 @@ namespace NzbDrone.Common.Disk
{
Ensure.That(path, () => path).IsValidPath(PathValidationType.CurrentOs);
foreach (var file in GetFiles(path, false))
foreach (var file in GetFiles(path, SearchOption.TopDirectoryOnly))
{
DeleteFile(file);
}
@@ -509,17 +504,13 @@ namespace NzbDrone.Common.Disk
return _fileSystem.DirectoryInfo.FromDirectoryName(path);
}
public List<IFileInfo> GetFileInfos(string path, bool recursive = false)
public List<IFileInfo> GetFileInfos(string path, SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
Ensure.That(path, () => path).IsValidPath(PathValidationType.CurrentOs);
var di = _fileSystem.DirectoryInfo.FromDirectoryName(path);
return di.EnumerateFiles("*", new EnumerationOptions
{
RecurseSubdirectories = recursive,
IgnoreInaccessible = true
}).ToList();
return di.GetFiles("*", searchOption).ToList();
}
public IFileInfo GetFileInfo(string path)

View File

@@ -23,8 +23,8 @@ namespace NzbDrone.Common.Disk
bool FileExists(string path, StringComparison stringComparison);
bool FolderWritable(string path);
bool FolderEmpty(string path);
IEnumerable<string> GetDirectories(string path);
IEnumerable<string> GetFiles(string path, bool recursive);
string[] GetDirectories(string path);
string[] GetFiles(string path, SearchOption searchOption);
long GetFolderSize(string path);
long GetFileSize(string path);
void CreateFolder(string path);
@@ -54,7 +54,7 @@ namespace NzbDrone.Common.Disk
IDirectoryInfo GetDirectoryInfo(string path);
List<IDirectoryInfo> GetDirectoryInfos(string path);
IFileInfo GetFileInfo(string path);
List<IFileInfo> GetFileInfos(string path, bool recursive = false);
List<IFileInfo> GetFileInfos(string path, SearchOption searchOption = SearchOption.TopDirectoryOnly);
void RemoveEmptySubfolders(string path);
void SaveStream(Stream stream, string path);
bool IsValidFolderPermissionMask(string mask);

View File

@@ -78,8 +78,8 @@ namespace NzbDrone.Common.EnvironmentInfo
}
if (IsLinux &&
(File.Exists("/.dockerenv") ||
(File.Exists("/proc/1/cgroup") && File.ReadAllText("/proc/1/cgroup").Contains("/docker/"))))
((File.Exists("/proc/1/cgroup") && File.ReadAllText("/proc/1/cgroup").Contains("/docker/")) ||
(File.Exists("/proc/1/mountinfo") && File.ReadAllText("/proc/1/mountinfo").Contains("/docker/"))))
{
IsDocker = true;
}

View File

@@ -140,7 +140,7 @@ namespace NzbDrone.Common.Extensions
public static bool IsPathValid(this string path, PathValidationType validationType)
{
if (string.IsNullOrWhiteSpace(path) || path.ContainsInvalidPathChars())
if (path.ContainsInvalidPathChars() || string.IsNullOrWhiteSpace(path))
{
return false;
}
@@ -160,11 +160,6 @@ namespace NzbDrone.Common.Extensions
public static bool ContainsInvalidPathChars(this string text)
{
if (text.IsNullOrWhiteSpace())
{
throw new ArgumentNullException("text");
}
return text.IndexOfAny(Path.GetInvalidPathChars()) >= 0;
}

View File

@@ -131,9 +131,9 @@ namespace NzbDrone.Common.Instrumentation
private static void RegisterAppFile(IAppFolderInfo appFolderInfo)
{
RegisterAppFile(appFolderInfo, "appFileInfo", "readarr.txt", 5, LogLevel.Info);
RegisterAppFile(appFolderInfo, "appFileDebug", "readarr.debug.txt", 50, LogLevel.Off);
RegisterAppFile(appFolderInfo, "appFileTrace", "readarr.trace.txt", 50, LogLevel.Off);
RegisterAppFile(appFolderInfo, "appFileInfo", "Readarr.txt", 5, LogLevel.Info);
RegisterAppFile(appFolderInfo, "appFileDebug", "Readarr.debug.txt", 50, LogLevel.Off);
RegisterAppFile(appFolderInfo, "appFileTrace", "Readarr.trace.txt", 50, LogLevel.Off);
}
private static void RegisterAppFile(IAppFolderInfo appFolderInfo, string name, string fileName, int maxArchiveFiles, LogLevel minLogLevel)

View File

@@ -31,10 +31,6 @@ namespace NzbDrone.Core.Test.DiskSpace
.Setup(x => x.All())
.Returns(new List<RootFolder>() { _rootDir });
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.FolderExists(_rootDir.Path))
.Returns(true);
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.GetMounts())
.Returns(new List<IMount>());

View File

@@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
.Returns(new[] { targetDir });
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFiles(targetDir, true))
.Setup(c => c.GetFiles(targetDir, SearchOption.AllDirectories))
.Returns(new[] { Path.Combine(targetDir, "somefile.flac") });
Mocker.GetMock<IDiskProvider>()

View File

@@ -82,7 +82,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
.Returns(new[] { targetDir });
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFiles(targetDir, true))
.Setup(c => c.GetFiles(targetDir, SearchOption.AllDirectories))
.Returns(new[] { Path.Combine(targetDir, "somefile.flac") });
Mocker.GetMock<IDiskProvider>()

View File

@@ -74,7 +74,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
.Returns(new[] { targetDir });
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFiles(targetDir, true))
.Setup(c => c.GetFiles(targetDir, SearchOption.AllDirectories))
.Returns(new[] { Path.Combine(targetDir, "somefile.flac") });
Mocker.GetMock<IDiskProvider>()

View File

@@ -1,89 +0,0 @@
using System;
using System.Collections.Generic;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.HealthCheck.Checks;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Notifications;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.HealthCheck.Checks
{
[TestFixture]
public class NotificationStatusCheckFixture : CoreTest<NotificationStatusCheck>
{
private List<INotification> _notifications = new List<INotification>();
private List<NotificationStatus> _blockedNotifications = new List<NotificationStatus>();
[SetUp]
public void SetUp()
{
Mocker.GetMock<INotificationFactory>()
.Setup(v => v.GetAvailableProviders())
.Returns(_notifications);
Mocker.GetMock<INotificationStatusService>()
.Setup(v => v.GetBlockedProviders())
.Returns(_blockedNotifications);
Mocker.GetMock<ILocalizationService>()
.Setup(s => s.GetLocalizedString(It.IsAny<string>()))
.Returns("Some Warning Message");
}
private Mock<INotification> GivenNotification(int id, double backoffHours, double failureHours)
{
var mockNotification = new Mock<INotification>();
mockNotification.SetupGet(s => s.Definition).Returns(new NotificationDefinition { Id = id });
_notifications.Add(mockNotification.Object);
if (backoffHours != 0.0)
{
_blockedNotifications.Add(new NotificationStatus
{
ProviderId = id,
InitialFailure = DateTime.UtcNow.AddHours(-failureHours),
MostRecentFailure = DateTime.UtcNow.AddHours(-0.1),
EscalationLevel = 5,
DisabledTill = DateTime.UtcNow.AddHours(backoffHours)
});
}
return mockNotification;
}
[Test]
public void should_not_return_error_when_no_notifications()
{
Subject.Check().ShouldBeOk();
}
[Test]
public void should_return_warning_if_notification_unavailable()
{
GivenNotification(1, 10.0, 24.0);
GivenNotification(2, 0.0, 0.0);
Subject.Check().ShouldBeWarning();
}
[Test]
public void should_return_error_if_all_notifications_unavailable()
{
GivenNotification(1, 10.0, 24.0);
Subject.Check().ShouldBeError();
}
[Test]
public void should_return_warning_if_few_notifications_unavailable()
{
GivenNotification(1, 10.0, 24.0);
GivenNotification(2, 10.0, 24.0);
GivenNotification(3, 0.0, 0.0);
Subject.Check().ShouldBeWarning();
}
}
}

View File

@@ -8,9 +8,7 @@ using NzbDrone.Core.Books;
using NzbDrone.Core.HealthCheck.Checks;
using NzbDrone.Core.ImportLists;
using NzbDrone.Core.Localization;
using NzbDrone.Core.RootFolders;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.HealthCheck.Checks
{
@@ -25,7 +23,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
.Returns("Some Warning Message");
}
private void GivenMissingRootFolder(string rootFolderPath)
private void GivenMissingRootFolder()
{
var author = Builder<Author>.CreateListOfSize(1)
.Build()
@@ -43,9 +41,9 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
.Setup(s => s.All())
.Returns(importList);
Mocker.GetMock<IRootFolderService>()
.Setup(s => s.GetBestRootFolderPath(It.IsAny<string>()))
.Returns(rootFolderPath);
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetParentFolder(author.First().Path))
.Returns(@"C:\Books");
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.FolderExists(It.IsAny<string>()))
@@ -69,25 +67,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
[Test]
public void should_return_error_if_book_parent_is_missing()
{
GivenMissingRootFolder(@"C:\Books".AsOsAgnostic());
Subject.Check().ShouldBeError();
}
[Test]
public void should_return_error_if_series_path_is_for_posix_os()
{
WindowsOnly();
GivenMissingRootFolder("/mnt/books");
Subject.Check().ShouldBeError();
}
[Test]
public void should_return_error_if_series_path_is_for_windows()
{
PosixOnly();
GivenMissingRootFolder(@"C:\Books");
GivenMissingRootFolder();
Subject.Check().ShouldBeError();
}

View File

@@ -1,56 +0,0 @@
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Housekeeping.Housekeepers;
using NzbDrone.Core.Notifications;
using NzbDrone.Core.Notifications.Join;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
{
[TestFixture]
public class CleanupOrphanedNotificationStatusFixture : DbTest<CleanupOrphanedNotificationStatus, NotificationStatus>
{
private NotificationDefinition _notification;
[SetUp]
public void Setup()
{
_notification = Builder<NotificationDefinition>.CreateNew()
.With(s => s.Settings = new JoinSettings { })
.BuildNew();
}
private void GivenNotification()
{
Db.Insert(_notification);
}
[Test]
public void should_delete_orphaned_notificationstatus()
{
var status = Builder<NotificationStatus>.CreateNew()
.With(h => h.ProviderId = _notification.Id)
.BuildNew();
Db.Insert(status);
Subject.Clean();
AllStoredModels.Should().BeEmpty();
}
[Test]
public void should_not_delete_unorphaned_notificationstatus()
{
GivenNotification();
var status = Builder<NotificationStatus>.CreateNew()
.With(h => h.ProviderId = _notification.Id)
.BuildNew();
Db.Insert(status);
Subject.Clean();
AllStoredModels.Should().HaveCount(1);
AllStoredModels.Should().Contain(h => h.ProviderId == _notification.Id);
}
}
}

View File

@@ -9,7 +9,6 @@ using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Books;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.MediaFiles;
@@ -67,26 +66,10 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
private void GivenRootFolder(params string[] subfolders)
{
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.FolderExists(_rootFolder))
.Returns(true);
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetDirectories(_rootFolder))
.Returns(subfolders);
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.FolderEmpty(_rootFolder))
.Returns(subfolders.Empty());
FileSystem.AddDirectory(_rootFolder);
foreach (var folder in subfolders)
{
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.FolderExists(folder))
.Returns(true);
FileSystem.AddDirectory(folder);
}
}
@@ -96,7 +79,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
GivenRootFolder(_author.Path);
}
private void GivenFiles(IEnumerable<string> files, DateTimeOffset? lastWrite = null)
private List<IFileInfo> GivenFiles(IEnumerable<string> files, DateTimeOffset? lastWrite = null)
{
if (lastWrite == null)
{
@@ -109,9 +92,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
FileSystem.AddFile(file, new MockFileData(string.Empty) { LastWriteTime = lastWrite.Value });
}
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetFileInfos(It.IsAny<string>(), true))
.Returns(files.Select(x => DiskProvider.GetFileInfo(x)).ToList());
return files.Select(x => DiskProvider.GetFileInfo(x)).ToList();
}
private void GivenKnownFiles(IEnumerable<string> files, DateTimeOffset? lastWrite = null)
@@ -158,7 +139,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
ExceptionVerification.ExpectedWarns(1);
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.GetFiles(_author.Path, true), Times.Never());
.Verify(v => v.GetFiles(_author.Path, SearchOption.AllDirectories), Times.Never());
Mocker.GetMock<IMediaFileTableCleanupService>()
.Verify(v => v.Clean(It.IsAny<string>(), It.IsAny<List<string>>()), Times.Never());
@@ -213,9 +194,6 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
Subject.Scan(new List<string> { _author.Path });
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.GetFileInfos(It.IsAny<string>(), It.IsAny<bool>()), Times.Once());
Mocker.GetMock<IMakeImportDecision>()
.Verify(v => v.GetImportDecisions(It.Is<List<IFileInfo>>(l => l.Count == 1), It.IsAny<IdentificationOverrides>(), It.IsAny<ImportDecisionMakerInfo>(), It.IsAny<ImportDecisionMakerConfig>()), Times.Once());
}
@@ -406,8 +384,6 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
[Test]
public void should_insert_new_unmatched_files_when_all_new()
{
GivenAuthorFolder();
var files = new List<string>
{
Path.Combine(_author.Path, "Season 1", "file1.mobi"),
@@ -428,8 +404,6 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
[Test]
public void should_insert_new_unmatched_files_when_some_known()
{
GivenAuthorFolder();
var files = new List<string>
{
Path.Combine(_author.Path, "Season 1", "file1.mobi"),
@@ -450,8 +424,6 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
[Test]
public void should_not_insert_files_when_all_known()
{
GivenAuthorFolder();
var files = new List<string>
{
Path.Combine(_author.Path, "Season 1", "file1.mobi"),
@@ -476,8 +448,6 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
[Test]
public void should_not_update_info_for_unchanged_known_files()
{
GivenAuthorFolder();
var files = new List<string>
{
Path.Combine(_author.Path, "Season 1", "file1.mobi"),
@@ -502,8 +472,6 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
[Test]
public void should_update_info_for_changed_known_files()
{
GivenAuthorFolder();
var files = new List<string>
{
Path.Combine(_author.Path, "Season 1", "file1.mobi"),

View File

@@ -85,8 +85,8 @@ namespace NzbDrone.Core.Test.MetadataSource.Goodreads
ExceptionVerification.IgnoreWarns();
}
[TestCase("Roald Dahl", 0, typeof(Author), new[] { "Roald Dahl" }, TestName = "author")]
[TestCase("Roald Dahl", 1, typeof(Book), new[] { "Going Solo", "Boy: Tales of Childhood" }, TestName = "book")]
[TestCase("Catherine Butler", 0, typeof(Author), new[] { "Catherine Butler" }, TestName = "author")]
[TestCase("Catherine Butler", 1, typeof(Book), new[] { "Twisted Winter", "Shattered Dreams" }, TestName = "book")]
public void successful_combined_search(string query, int position, Type resultType, string[] expected)
{
var result = Subject.SearchForNewEntity(query);

View File

@@ -1,161 +0,0 @@
using System;
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Notifications;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.NotificationTests
{
public class NotificationStatusServiceFixture : CoreTest<NotificationStatusService>
{
private DateTime _epoch;
[SetUp]
public void SetUp()
{
_epoch = DateTime.UtcNow;
Mocker.GetMock<IRuntimeInfo>()
.SetupGet(v => v.StartTime)
.Returns(_epoch - TimeSpan.FromHours(1));
}
private NotificationStatus WithStatus(NotificationStatus status)
{
Mocker.GetMock<INotificationStatusRepository>()
.Setup(v => v.FindByProviderId(1))
.Returns(status);
Mocker.GetMock<INotificationStatusRepository>()
.Setup(v => v.All())
.Returns(new[] { status });
return status;
}
private void VerifyUpdate()
{
Mocker.GetMock<INotificationStatusRepository>()
.Verify(v => v.Upsert(It.IsAny<NotificationStatus>()), Times.Once());
}
private void VerifyNoUpdate()
{
Mocker.GetMock<INotificationStatusRepository>()
.Verify(v => v.Upsert(It.IsAny<NotificationStatus>()), Times.Never());
}
[Test]
public void should_not_consider_blocked_within_5_minutes_since_initial_failure()
{
WithStatus(new NotificationStatus
{
InitialFailure = _epoch - TimeSpan.FromMinutes(4),
MostRecentFailure = _epoch - TimeSpan.FromSeconds(4),
EscalationLevel = 3
});
Subject.RecordFailure(1);
VerifyUpdate();
var status = Subject.GetBlockedProviders().FirstOrDefault();
status.Should().BeNull();
}
[Test]
public void should_consider_blocked_after_5_minutes_since_initial_failure()
{
WithStatus(new NotificationStatus
{
InitialFailure = _epoch - TimeSpan.FromMinutes(6),
MostRecentFailure = _epoch - TimeSpan.FromSeconds(120),
EscalationLevel = 3
});
Subject.RecordFailure(1);
VerifyUpdate();
var status = Subject.GetBlockedProviders().FirstOrDefault();
status.Should().NotBeNull();
}
[Test]
public void should_not_escalate_further_till_after_5_minutes_since_initial_failure()
{
var origStatus = WithStatus(new NotificationStatus
{
InitialFailure = _epoch - TimeSpan.FromMinutes(4),
MostRecentFailure = _epoch - TimeSpan.FromSeconds(4),
EscalationLevel = 3
});
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
var status = Subject.GetBlockedProviders().FirstOrDefault();
status.Should().BeNull();
origStatus.EscalationLevel.Should().Be(3);
}
[Test]
public void should_escalate_further_after_5_minutes_since_initial_failure()
{
WithStatus(new NotificationStatus
{
InitialFailure = _epoch - TimeSpan.FromMinutes(6),
MostRecentFailure = _epoch - TimeSpan.FromSeconds(120),
EscalationLevel = 3
});
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
var status = Subject.GetBlockedProviders().FirstOrDefault();
status.Should().NotBeNull();
status.EscalationLevel.Should().BeGreaterThan(3);
}
[Test]
public void should_not_escalate_beyond_3_hours()
{
WithStatus(new NotificationStatus
{
InitialFailure = _epoch - TimeSpan.FromMinutes(6),
MostRecentFailure = _epoch - TimeSpan.FromSeconds(120),
EscalationLevel = 3
});
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
var status = Subject.GetBlockedProviders().FirstOrDefault();
status.Should().NotBeNull();
status.DisabledTill.Should().HaveValue();
status.DisabledTill.Should().NotBeAfter(_epoch + TimeSpan.FromHours(3.1));
}
}
}

View File

@@ -32,7 +32,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
};
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetFileInfos(It.IsAny<string>(), It.IsAny<bool>()))
.Setup(s => s.GetFileInfos(It.IsAny<string>(), It.IsAny<SearchOption>()))
.Returns(new List<IFileInfo>());
}
@@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
}
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetFileInfos(It.IsAny<string>(), true))
.Setup(s => s.GetFileInfos(It.IsAny<string>(), SearchOption.AllDirectories))
.Returns(filesToReturn);
}
@@ -60,8 +60,8 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
{
Subject.GetBookFiles(_path);
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(_path, true), Times.Once());
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(_path, false), Times.Never());
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(_path, SearchOption.AllDirectories), Times.Once());
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(_path, SearchOption.TopDirectoryOnly), Times.Never());
}
[Test]
@@ -69,8 +69,8 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
{
Subject.GetBookFiles(_path, true);
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(_path, true), Times.Once());
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(_path, false), Times.Never());
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(_path, SearchOption.AllDirectories), Times.Once());
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(_path, SearchOption.TopDirectoryOnly), Times.Never());
}
[Test]
@@ -78,8 +78,8 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
{
Subject.GetBookFiles(_path, false);
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(_path, true), Times.Never());
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(_path, false), Times.Once());
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(_path, SearchOption.AllDirectories), Times.Never());
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(_path, SearchOption.TopDirectoryOnly), Times.Once());
}
[Test]

View File

@@ -1,4 +1,5 @@
using System;
using System;
using System.IO;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
@@ -41,7 +42,7 @@ namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests
Mocker.GetMock<IDiskProvider>().Setup(s => s.GetDirectories(RecycleBin))
.Returns(new[] { @"C:\Test\RecycleBin\Folder1", @"C:\Test\RecycleBin\Folder2", @"C:\Test\RecycleBin\Folder3" });
Mocker.GetMock<IDiskProvider>().Setup(s => s.GetFiles(RecycleBin, true))
Mocker.GetMock<IDiskProvider>().Setup(s => s.GetFiles(RecycleBin, SearchOption.AllDirectories))
.Returns(new[] { @"C:\Test\RecycleBin\File1.avi", @"C:\Test\RecycleBin\File2.mkv" });
}

View File

@@ -1,4 +1,5 @@
using System;
using System;
using System.IO;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
@@ -67,7 +68,7 @@ namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests
WithRecycleBin();
var path = @"C:\Test\TV\30 Rock".AsOsAgnostic();
Mocker.GetMock<IDiskProvider>().Setup(s => s.GetFiles(@"C:\Test\Recycle Bin\30 Rock".AsOsAgnostic(), true))
Mocker.GetMock<IDiskProvider>().Setup(s => s.GetFiles(@"C:\Test\Recycle Bin\30 Rock".AsOsAgnostic(), SearchOption.AllDirectories))
.Returns(new[] { "File1", "File2", "File3" });
Mocker.Resolve<RecycleBinProvider>().DeleteFolder(path);

View File

@@ -1,3 +1,4 @@
using System.IO;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
@@ -21,7 +22,7 @@ namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests
Mocker.GetMock<IDiskProvider>().Setup(s => s.GetDirectories(RecycleBin))
.Returns(new[] { @"C:\Test\RecycleBin\Folder1", @"C:\Test\RecycleBin\Folder2", @"C:\Test\RecycleBin\Folder3" });
Mocker.GetMock<IDiskProvider>().Setup(s => s.GetFiles(RecycleBin, false))
Mocker.GetMock<IDiskProvider>().Setup(s => s.GetFiles(RecycleBin, SearchOption.TopDirectoryOnly))
.Returns(new[] { @"C:\Test\RecycleBin\File1.avi", @"C:\Test\RecycleBin\File2.mkv" });
}

View File

@@ -1,6 +1,8 @@
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Core.RootFolders;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
@@ -20,46 +22,27 @@ namespace NzbDrone.Core.Test.RootFolderTests
[Test]
public void should_return_root_folder_that_is_parent_path()
{
GivenRootFolders(@"C:\Test\Books".AsOsAgnostic(), @"D:\Test\Books".AsOsAgnostic());
Subject.GetBestRootFolderPath(@"C:\Test\Books\Author Title".AsOsAgnostic()).Should().Be(@"C:\Test\Books".AsOsAgnostic());
GivenRootFolders(@"C:\Test\Music".AsOsAgnostic(), @"D:\Test\Music".AsOsAgnostic());
Subject.GetBestRootFolderPath(@"C:\Test\Music\Series Title".AsOsAgnostic()).Should().Be(@"C:\Test\Music".AsOsAgnostic());
}
[Test]
public void should_return_root_folder_that_is_grandparent_path()
{
GivenRootFolders(@"C:\Test\Books".AsOsAgnostic(), @"D:\Test\Books".AsOsAgnostic());
Subject.GetBestRootFolderPath(@"C:\Test\Books\S\Author Title".AsOsAgnostic()).Should().Be(@"C:\Test\Books".AsOsAgnostic());
GivenRootFolders(@"C:\Test\Music".AsOsAgnostic(), @"D:\Test\Music".AsOsAgnostic());
Subject.GetBestRootFolderPath(@"C:\Test\Music\S\Series Title".AsOsAgnostic()).Should().Be(@"C:\Test\Music".AsOsAgnostic());
}
[Test]
public void should_get_parent_path_from_os_path_if_matching_root_folder_is_not_found()
public void should_get_parent_path_from_diskProvider_if_matching_root_folder_is_not_found()
{
var artistPath = @"T:\Test\Books\Author Title".AsOsAgnostic();
var seriesPath = @"T:\Test\Music\Series Title".AsOsAgnostic();
GivenRootFolders(@"C:\Test\Books".AsOsAgnostic(), @"D:\Test\Books".AsOsAgnostic());
Subject.GetBestRootFolderPath(artistPath).Should().Be(@"T:\Test\Books".AsOsAgnostic());
}
GivenRootFolders(@"C:\Test\Music".AsOsAgnostic(), @"D:\Test\Music".AsOsAgnostic());
Subject.GetBestRootFolderPath(seriesPath);
[Test]
public void should_get_parent_path_from_os_path_if_matching_root_folder_is_not_found_for_posix_path()
{
WindowsOnly();
var artistPath = "/mnt/books/Author Title";
GivenRootFolders(@"C:\Test\Books".AsOsAgnostic(), @"D:\Test\Books".AsOsAgnostic());
Subject.GetBestRootFolderPath(artistPath).Should().Be(@"/mnt/books");
}
[Test]
public void should_get_parent_path_from_os_path_if_matching_root_folder_is_not_found_for_windows_path()
{
PosixOnly();
var artistPath = @"T:\Test\Books\Author Title";
GivenRootFolders(@"C:\Test\Books".AsOsAgnostic(), @"D:\Test\Books".AsOsAgnostic());
Subject.GetBestRootFolderPath(artistPath).Should().Be(@"T:\Test\Books");
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.GetParentFolder(seriesPath), Times.Once);
}
}
}

View File

@@ -34,7 +34,6 @@ namespace NzbDrone.Core.Test.ThingiProviderTests
public class ProviderStatusServiceFixture : CoreTest<MockProviderStatusService>
{
private readonly TimeSpan _disabledTillPrecision = TimeSpan.FromMilliseconds(500);
private DateTime _epoch;
[SetUp]
@@ -91,7 +90,7 @@ namespace NzbDrone.Core.Test.ThingiProviderTests
var status = Subject.GetBlockedProviders().FirstOrDefault();
status.Should().NotBeNull();
status.DisabledTill.Should().HaveValue();
status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(1), _disabledTillPrecision);
status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(5), 500);
}
[Test]
@@ -134,7 +133,7 @@ namespace NzbDrone.Core.Test.ThingiProviderTests
var status = Subject.GetBlockedProviders().FirstOrDefault();
status.Should().NotBeNull();
status.DisabledTill.Should().HaveValue();
status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(5), _disabledTillPrecision);
status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(15), 500);
}
[Test]
@@ -161,7 +160,7 @@ namespace NzbDrone.Core.Test.ThingiProviderTests
status.Should().NotBeNull();
origStatus.EscalationLevel.Should().Be(3);
status.DisabledTill.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(5), _disabledTillPrecision);
status.DisabledTill.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(5), 500);
}
}
}

View File

@@ -90,6 +90,17 @@ namespace NzbDrone.Core.Test.UpdateTests
.Returns(true);
}
[Test]
public void should_not_update_if_inside_docker()
{
Mocker.GetMock<IOsInfo>().Setup(x => x.IsDocker).Returns(true);
Subject.Execute(new ApplicationUpdateCommand());
Mocker.GetMock<IProcessProvider>()
.Verify(c => c.Start(It.IsAny<string>(), It.Is<string>(s => s.StartsWith("12")), null, null, null), Times.Never());
}
[Test]
public void should_delete_sandbox_before_update_if_folder_exists()
{
@@ -328,28 +339,6 @@ namespace NzbDrone.Core.Test.UpdateTests
.Verify(v => v.SaveConfigDictionary(It.Is<Dictionary<string, object>>(d => d.ContainsKey("Branch") && (string)d["Branch"] == "fake")), Times.Once());
}
[Test]
public void should_not_update_with_built_in_updater_inside_docker_container()
{
Mocker.GetMock<IDeploymentInfoProvider>().Setup(x => x.PackageUpdateMechanism).Returns(UpdateMechanism.Docker);
Subject.Execute(new ApplicationUpdateCommand());
Mocker.GetMock<IProcessProvider>()
.Verify(c => c.Start(It.IsAny<string>(), It.Is<string>(s => s.StartsWith("12")), null, null, null), Times.Never());
}
[Test]
public void should_not_update_with_built_in_updater_when_external_updater_is_configured()
{
Mocker.GetMock<IDeploymentInfoProvider>().Setup(x => x.IsExternalUpdateMechanism).Returns(true);
Subject.Execute(new ApplicationUpdateCommand());
Mocker.GetMock<IProcessProvider>()
.Verify(c => c.Start(It.IsAny<string>(), It.Is<string>(s => s.StartsWith("12")), null, null, null), Times.Never());
}
[TearDown]
public void TearDown()
{

View File

@@ -89,7 +89,7 @@ namespace NzbDrone.Core.Backup
// Delete journal file created during database backup
_diskProvider.DeleteFile(Path.Combine(_backupTempFolder, "readarr.db-journal"));
_archiveService.CreateZip(backupPath, _diskProvider.GetFiles(_backupTempFolder, false));
_archiveService.CreateZip(backupPath, _diskProvider.GetFiles(_backupTempFolder, SearchOption.TopDirectoryOnly));
Cleanup();
@@ -128,7 +128,7 @@ namespace NzbDrone.Core.Backup
_archiveService.Extract(backupFileName, temporaryPath);
foreach (var file in _diskProvider.GetFiles(temporaryPath, false))
foreach (var file in _diskProvider.GetFiles(temporaryPath, SearchOption.TopDirectoryOnly))
{
var fileName = Path.GetFileName(file);
@@ -237,7 +237,7 @@ namespace NzbDrone.Core.Backup
private IEnumerable<string> GetBackupFiles(string path)
{
var files = _diskProvider.GetFiles(path, false);
var files = _diskProvider.GetFiles(path, SearchOption.TopDirectoryOnly);
return files.Where(f => BackupFileRegex.IsMatch(f));
}

View File

@@ -1,19 +0,0 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(037)]
public class add_notification_status : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Create.TableForModel("NotificationStatus")
.WithColumn("ProviderId").AsInt32().NotNullable().Unique()
.WithColumn("InitialFailure").AsDateTimeOffset().Nullable()
.WithColumn("MostRecentFailure").AsDateTimeOffset().Nullable()
.WithColumn("EscalationLevel").AsInt32().NotNullable()
.WithColumn("DisabledTill").AsDateTimeOffset().Nullable();
}
}
}

View File

@@ -202,7 +202,6 @@ namespace NzbDrone.Core.Datastore
Mapper.Entity<IndexerStatus>("IndexerStatus").RegisterModel();
Mapper.Entity<DownloadClientStatus>("DownloadClientStatus").RegisterModel();
Mapper.Entity<ImportListStatus>("ImportListStatus").RegisterModel();
Mapper.Entity<NotificationStatus>("NotificationStatus").RegisterModel();
Mapper.Entity<CustomFilter>("CustomFilters").RegisterModel();
Mapper.Entity<ImportListExclusion>("ImportListExclusions").RegisterModel();

View File

@@ -5,7 +5,6 @@ using System.Linq;
using System.Text.RegularExpressions;
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.RootFolders;
namespace NzbDrone.Core.DiskSpace
@@ -34,7 +33,7 @@ namespace NzbDrone.Core.DiskSpace
public List<DiskSpace> GetFreeSpace()
{
var importantRootFolders = GetRootPaths().Distinct().ToList();
var importantRootFolders = _rootFolderService.All().Select(x => x.Path).ToList();
var optionalRootFolders = GetFixedDisksRootPaths().Except(importantRootFolders).Distinct().ToList();
@@ -43,14 +42,6 @@ namespace NzbDrone.Core.DiskSpace
return diskSpace;
}
private IEnumerable<string> GetRootPaths()
{
return _rootFolderService.All()
.Select(x => x.Path)
.Where(path => path.IsPathValid(PathValidationType.CurrentOs) && _diskProvider.FolderExists(path))
.Distinct();
}
private IEnumerable<string> GetFixedDisksRootPaths()
{
return _diskProvider.GetMounts()

View File

@@ -69,7 +69,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
if (PreCheckWatchItemExpiry(newWatchItem, oldWatchItem))
{
var files = _diskProvider.GetFiles(folder, true);
var files = _diskProvider.GetFiles(folder, SearchOption.AllDirectories);
newWatchItem.TotalSize = files.Select(_diskProvider.GetFileSize).Sum();
newWatchItem.Hash = GetHash(folder, files);
@@ -153,7 +153,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
}
}
private string GetHash(string folder, IEnumerable<string> files)
private string GetHash(string folder, string[] files)
{
var data = new StringBuilder();

View File

@@ -61,7 +61,7 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
public override IEnumerable<DownloadClientItem> GetItems()
{
foreach (var file in _diskProvider.GetFiles(Settings.StrmFolder, false))
foreach (var file in _diskProvider.GetFiles(Settings.StrmFolder, SearchOption.TopDirectoryOnly))
{
if (Path.GetExtension(file) != ".strm")
{

View File

@@ -280,7 +280,6 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
if (config.DhtEnabled)
{
item.Status = DownloadItemStatus.Queued;
item.Message = "qBittorrent is downloading metadata";
}
else
{

View File

@@ -56,11 +56,11 @@ namespace NzbDrone.Core.Download
private IEnumerable<IDownloadClient> FilterBlockedClients(IEnumerable<IDownloadClient> clients)
{
var blockedClients = _downloadClientStatusService.GetBlockedProviders().ToDictionary(v => v.ProviderId, v => v);
var blockedIndexers = _downloadClientStatusService.GetBlockedProviders().ToDictionary(v => v.ProviderId, v => v);
foreach (var client in clients)
{
if (blockedClients.TryGetValue(client.Definition.Id, out var downloadClientStatus))
if (blockedIndexers.TryGetValue(client.Definition.Id, out var downloadClientStatus))
{
_logger.Debug("Temporarily ignoring download client {0} till {1} due to recent failures.", client.Definition.Name, downloadClientStatus.DisabledTill.Value.ToLocalTime());
continue;

View File

@@ -64,7 +64,7 @@ namespace NzbDrone.Core.Extras
var sourcePath = localBook.Path;
var sourceFolder = _diskProvider.GetParentFolder(sourcePath);
var sourceFileName = Path.GetFileNameWithoutExtension(sourcePath);
var files = _diskProvider.GetFiles(sourceFolder, false);
var files = _diskProvider.GetFiles(sourceFolder, SearchOption.TopDirectoryOnly);
var wantedExtensions = _configService.ExtraFileExtensions.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(e => e.Trim(' ', '.'))

View File

@@ -1,52 +0,0 @@
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Notifications;
using NzbDrone.Core.ThingiProvider.Events;
namespace NzbDrone.Core.HealthCheck.Checks
{
[CheckOn(typeof(ProviderUpdatedEvent<INotification>))]
[CheckOn(typeof(ProviderDeletedEvent<INotification>))]
[CheckOn(typeof(ProviderStatusChangedEvent<INotification>))]
public class NotificationStatusCheck : HealthCheckBase
{
private readonly INotificationFactory _providerFactory;
private readonly INotificationStatusService _providerStatusService;
public NotificationStatusCheck(INotificationFactory providerFactory, INotificationStatusService providerStatusService, ILocalizationService localizationService)
: base(localizationService)
{
_providerFactory = providerFactory;
_providerStatusService = providerStatusService;
}
public override HealthCheck Check()
{
var enabledProviders = _providerFactory.GetAvailableProviders();
var backOffProviders = enabledProviders.Join(_providerStatusService.GetBlockedProviders(),
i => i.Definition.Id,
s => s.ProviderId,
(i, s) => new { Provider = i, Status = s })
.ToList();
if (backOffProviders.Empty())
{
return new HealthCheck(GetType());
}
if (backOffProviders.Count == enabledProviders.Count)
{
return new HealthCheck(GetType(),
HealthCheckResult.Error,
_localizationService.GetLocalizedString("NotificationStatusAllClientHealthCheckMessage"),
"#notifications-are-unavailable-due-to-failures");
}
return new HealthCheck(GetType(),
HealthCheckResult.Warning,
string.Format(_localizationService.GetLocalizedString("NotificationStatusSingleClientHealthCheckMessage"), string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name))),
"#notifications-are-unavailable-due-to-failures");
}
}
}

View File

@@ -1,6 +1,5 @@
using System.Linq;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Books;
using NzbDrone.Core.Books.Events;
using NzbDrone.Core.ImportLists;
@@ -36,8 +35,8 @@ namespace NzbDrone.Core.HealthCheck.Checks
.Select(s => _rootFolderService.GetBestRootFolderPath(s.Value))
.Distinct();
var missingRootFolders = rootFolders.Where(s => !s.IsPathValid(PathValidationType.CurrentOs) || !_diskProvider.FolderExists(s))
.ToList();
var missingRootFolders = rootFolders.Where(s => !_diskProvider.FolderExists(s))
.ToList();
missingRootFolders.AddRange(_importListFactory.All()
.Select(s => s.RootFolderPath)

View File

@@ -1,4 +1,4 @@
using Dapper;
using Dapper;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Housekeeping.Housekeepers

View File

@@ -1,27 +0,0 @@
using Dapper;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Housekeeping.Housekeepers
{
public class CleanupOrphanedNotificationStatus : IHousekeepingTask
{
private readonly IMainDatabase _database;
public CleanupOrphanedNotificationStatus(IMainDatabase database)
{
_database = database;
}
public void Clean()
{
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""NotificationStatus""
WHERE ""Id"" IN (
SELECT ""NotificationStatus"".""Id"" FROM ""NotificationStatus""
LEFT OUTER JOIN ""Notifications""
ON ""NotificationStatus"".""ProviderId"" = ""Notifications"".""Id""
WHERE ""Notifications"".""Id"" IS NULL)");
}
}
}

View File

@@ -1,12 +0,0 @@
using NzbDrone.Core.Notifications;
namespace NzbDrone.Core.Housekeeping.Housekeepers
{
public class FixFutureNotificationStatusTimes : FixFutureProviderStatusTimes<NotificationStatus>, IHousekeepingTask
{
public FixFutureNotificationStatusTimes(INotificationStatusRepository notificationStatusRepository)
: base(notificationStatusRepository)
{
}
}
}

View File

@@ -603,30 +603,5 @@
"SetTags": "تعيين العلامات",
"Yes": "نعم",
"ApplyTagsHelpTextHowToApplyAuthors": "كيفية تطبيق العلامات على الأفلام المختارة",
"ApplyTagsHelpTextHowToApplyDownloadClients": "كيفية تطبيق العلامات على الأفلام المختارة",
"Small": "صغير",
"TotalSpace": "المساحة الكلية",
"Ui": "واجهة المستخدم",
"RecentChanges": "التغييرات الأخيرة",
"FreeSpace": "مساحة فارغة",
"LastExecution": "آخر تنفيذ",
"LastWriteTime": "وقت الكتابة الأخير",
"Location": "موقعك",
"Medium": "متوسط",
"NextExecution": "التنفيذ القادم",
"NoResultsFound": "لم يتم العثور على نتائج",
"NotificationStatusAllClientHealthCheckMessage": "جميع القوائم غير متاحة بسبب الإخفاقات",
"NotificationStatusSingleClientHealthCheckMessage": "القوائم غير متاحة بسبب الإخفاقات: {0}",
"SomeResultsAreHiddenByTheAppliedFilter": "بعض النتائج مخفية بواسطة عامل التصفية المطبق",
"ConnectionLost": "انقطع الاتصال",
"ConnectionLostReconnect": "سيحاول Radarr الاتصال تلقائيًا ، أو يمكنك النقر فوق إعادة التحميل أدناه.",
"LastDuration": "المدة الماضية",
"Large": "كبير",
"WhatsNew": "ما هو الجديد؟",
"Events": "الأحداث",
"Activity": "نشاط",
"AddNew": "اضف جديد",
"System": "النظام",
"AllResultsAreHiddenByTheAppliedFilter": "يتم إخفاء جميع النتائج بواسطة عامل التصفية المطبق",
"Backup": "دعم"
"ApplyTagsHelpTextHowToApplyDownloadClients": "كيفية تطبيق العلامات على الأفلام المختارة"
}

View File

@@ -602,29 +602,5 @@
"SetTags": "Задаване на маркери",
"Yes": "Да",
"ApplyTagsHelpTextHowToApplyAuthors": "Как да приложите тагове към избраните филми",
"ApplyTagsHelpTextHowToApplyDownloadClients": "Как да приложите тагове към избраните филми",
"NotificationStatusAllClientHealthCheckMessage": "Всички списъци са недостъпни поради неуспехи",
"NotificationStatusSingleClientHealthCheckMessage": "Списъци, недостъпни поради неуспехи: {0}",
"Small": "Малък",
"System": "Система",
"Ui": "Потребителски интерфейс",
"ConnectionLostReconnect": "Radarr ще се опита да се свърже автоматично или можете да щракнете върху презареждане по-долу.",
"TotalSpace": "Общо пространство",
"Events": "Събития",
"Large": "Голям",
"LastDuration": "lastDuration",
"LastExecution": "Последно изпълнение",
"LastWriteTime": "Време за последно писане",
"Location": "Местоположение",
"NoResultsFound": "Няма намерени резултати",
"SomeResultsAreHiddenByTheAppliedFilter": "Някои резултати са скрити от прилагания филтър",
"RecentChanges": "Последни промени",
"WhatsNew": "Какво ново?",
"FreeSpace": "Свободно пространство",
"Medium": "Среден",
"Activity": "Дейност",
"AddNew": "Добави нов",
"NextExecution": "Следващо изпълнение",
"AllResultsAreHiddenByTheAppliedFilter": "Всички резултати са скрити от приложения филтър",
"Backup": "Архивиране"
"ApplyTagsHelpTextHowToApplyDownloadClients": "Как да приложите тагове към избраните филми"
}

View File

@@ -1,5 +1,4 @@
{
"About": "সম্পর্কিত",
"Actions": "ক্রিয়াকাণ্ড",
"Activity": "কার্যকলাপ"
"Actions": "ক্রিয়াকাণ্ড"
}

View File

@@ -605,31 +605,5 @@
"ApplyTagsHelpTextReplace": "Nahradit: Nahradit tagy zadanými tagy (pro vymazání všech tagů zadejte žádné tagy)",
"DeleteSelectedDownloadClients": "Odstranit staženého klienta",
"DeleteSelectedIndexersMessageText": "Opravdu chcete odstranit indexer „{0}“?",
"Yes": "Ano",
"NotificationStatusAllClientHealthCheckMessage": "Všechny seznamy nejsou k dispozici z důvodu selhání",
"Small": "Malý",
"LastExecution": "Poslední poprava",
"LastWriteTime": "Čas posledního zápisu",
"Location": "Umístění",
"NotificationStatusSingleClientHealthCheckMessage": "Seznamy nejsou k dispozici z důvodu selhání: {0}",
"RecentChanges": "Nedávné změny",
"Backup": "Záloha",
"Medium": "Střední",
"NoResultsFound": "Nebyly nalezeny žádné výsledky",
"SomeResultsAreHiddenByTheAppliedFilter": "Některé výsledky jsou použitým filtrem skryty",
"AllResultsAreHiddenByTheAppliedFilter": "Všechny výsledky jsou skryty použitým filtrem",
"Events": "Události",
"FreeSpace": "Volný prostor",
"System": "Systém",
"TotalSpace": "Celkový prostor",
"ConnectionLost": "Spojení ztraceno",
"ConnectionLostReconnect": "Radarr se pokusí připojit automaticky, nebo můžete kliknout na znovu načíst níže.",
"ConnectionLostToBackend": "Radarr ztratil spojení s back-endem a pro obnovení funkčnosti bude nutné jej znovu načíst.",
"Large": "Velký",
"LastDuration": "lastDuration",
"Ui": "UI",
"WhatsNew": "Co je nového?",
"Activity": "Aktivita",
"AddNew": "Přidat nový",
"NextExecution": "Další spuštění"
"Yes": "Ano"
}

View File

@@ -608,31 +608,5 @@
"DeleteSelectedIndexers": "Slet Indexer",
"ExistingTag": "Eksisterende mærke",
"SetTags": "Indstil tags",
"Yes": "Ja",
"NotificationStatusAllClientHealthCheckMessage": "Alle lister er utilgængelige på grund af fejl",
"NotificationStatusSingleClientHealthCheckMessage": "Lister utilgængelige på grund af fejl: {0}",
"Small": "Lille",
"TotalSpace": "Samlet plads",
"Ui": "UI",
"Events": "Begivenheder",
"LastDuration": "Seneste varighed",
"LastExecution": "Seneste udførelse",
"LastWriteTime": "Sidste Skrive Tid",
"Medium": "Medium",
"System": "System",
"NextExecution": "Næste udførelse",
"NoResultsFound": "Ingen resultater fundet",
"ConnectionLost": "Forbindelse Mistet",
"ConnectionLostReconnect": "Radarr vil prøve at tilslutte automatisk, eller du kan klikke genindlæs forneden.",
"Location": "Beliggenhed",
"RecentChanges": "Seneste ændringer",
"SomeResultsAreHiddenByTheAppliedFilter": "Nogle resultater skjules af det anvendte filter",
"WhatsNew": "Hvad er nyt?",
"FreeSpace": "Frit Plads",
"Backup": "Backup",
"Activity": "Aktivitet",
"AddNew": "Tilføj Ny",
"Large": "Stor",
"Library": "Bibliotek",
"AllResultsAreHiddenByTheAppliedFilter": "Alle resultater skjules af det anvendte filter"
"Yes": "Ja"
}

View File

@@ -968,32 +968,5 @@
"NoChange": "Keine Änderung",
"NoDownloadClientsFound": "Keine Download Clienten gefunden",
"SetTags": "Tags setzen",
"Loading": "Lade",
"ConnectionLostReconnect": "Radarr wird automatisch versuchen zu verbinden oder klicke unten auf neuladen.",
"ConnectionLostToBackend": "Radarr hat die Verbindung zum Backend verloren und muss neugeladen werden.",
"NotificationStatusAllClientHealthCheckMessage": "Wegen Fehlern sind keine Applikationen verfügbar",
"NotificationStatusSingleClientHealthCheckMessage": "Applikationen wegen folgender Fehler nicht verfügbar: {0}",
"TotalSpace": "Speicherkapazität",
"Ui": "Oberfläche",
"FreeSpace": "Freier Speicher",
"Large": "Groß",
"LastExecution": "Letzte Ausführung",
"LastWriteTime": "Zuletzt beschrieben",
"Library": "Bibliothek",
"Location": "Speicherort",
"Small": "Klein",
"ConnectionLost": "Verbindung unterbrochen",
"Events": "Events",
"LastDuration": "Letzte Dauer",
"RecentChanges": "Neuste Änderungen",
"System": "System",
"WhatsNew": "Was gibt's Neues?",
"NextExecution": "Nächste Ausführung",
"NoResultsFound": "Keine Ergebnisse gefunden",
"SomeResultsAreHiddenByTheAppliedFilter": "Einige Ergebnisse werden wegen der aktiven Filter nicht angezeigt",
"Medium": "Medium",
"Activity": "Aktivität",
"AddNew": "Hinzufügen",
"Backup": "Backups",
"AllResultsAreHiddenByTheAppliedFilter": "Keine Ergebnisse mit den ausgewählten Filtern"
"Loading": "Lade"
}

View File

@@ -965,33 +965,5 @@
"RemoveFailed": "Η αφαίρεση απέτυχε",
"RemoveFailedDownloads": "Αφαίρεση Αποτυχημένων Λήψεων",
"SetTags": "Ορισμός ετικετών",
"Yes": "Ναί",
"ConnectionLostToBackend": "Το Radarr έχασε τη σύνδεσή του με το backend και θα χρειαστεί να επαναφορτωθεί για να αποκαταστήσει τη λειτουργικότητά του.",
"AllResultsAreHiddenByTheAppliedFilter": "Όλα τα αποτελέσματα αποκρύπτονται από το εφαρμοσμένο φίλτρο",
"NotificationStatusAllClientHealthCheckMessage": "Όλες οι λίστες δεν είναι διαθέσιμες λόγω αστοχιών",
"NotificationStatusSingleClientHealthCheckMessage": "Μη διαθέσιμες λίστες λόγω αποτυχιών: {0}",
"TotalSpace": "Συνολικός χώρος",
"Ui": "Διεπαφή χρήστη",
"NoResultsFound": "Δεν βρέθηκαν αποτελέσματα",
"Events": "Γεγονότα",
"Large": "Μεγάλο",
"LastDuration": "Τελευταία Διάρκεια",
"LastExecution": "Τελευταία εκτέλεση",
"LastWriteTime": "Τελευταία ώρα εγγραφής",
"Library": "Βιβλιοθήκη",
"Location": "Τοποθεσία",
"System": "Σύστημα",
"FreeSpace": "Ελεύθερος Χώρος",
"SkipRedownloadHelpText": "Αποτρέπει το Lidarr από το να δοκιμάσει τη λήψη εναλλακτικών εκδόσεων για τα αφαιρεμένα στοιχεία",
"Medium": "Μεσαίο",
"ConnectionLost": "Η σύνδεση χάθηκε",
"ConnectionLostReconnect": "Το Radarr θα προσπαθήσει να συνδεθεί αυτόματα, αλλιώς μπορείτε να κάνετε reload απο κάτω.",
"RecentChanges": "Πρόσφατες αλλαγές",
"SomeResultsAreHiddenByTheAppliedFilter": "Ορισμένα αποτελέσματα αποκρύπτονται από το εφαρμοσμένο φίλτρο",
"WhatsNew": "Τι νέα?",
"Activity": "Δραστηριότητα",
"AddNew": "Προσθήκη Νέων",
"Backup": "Αντίγραφο Ασφαλείας",
"NextExecution": "Επόμενη εκτέλεση",
"Small": "Μικρό"
"Yes": "Ναί"
}

View File

@@ -21,7 +21,6 @@
"AllBooks": "All Books",
"AllExpandedCollapseAll": "Collapse All",
"AllExpandedExpandAll": "Expand All",
"AllResultsAreHiddenByTheAppliedFilter": "All results are hidden by the applied filter",
"AllowAuthorChangeClickToChangeAuthor": "Click to change author",
"AllowFingerprinting": "Allow Fingerprinting",
"AllowFingerprintingHelpText": "Use fingerprinting to improve accuracy of book matching",
@@ -37,8 +36,6 @@
"ApiKeyValidationHealthCheckMessage": "Please update your API key to be at least {0} characters long. You can do this via settings or the config file",
"AppDataDirectory": "AppData directory",
"AppDataLocationHealthCheckMessage": "Updating will not be possible to prevent deleting AppData on Update",
"AppUpdated": "{appName} Updated",
"AppUpdatedVersion": "{appName} has been updated to version `{version}`, in order to get the latest changes you'll need to reload {appName}",
"ApplicationURL": "Application URL",
"ApplicationUrlHelpText": "This application's external URL including http(s)://, port and URL base",
"ApplyChanges": "Apply Changes",
@@ -65,7 +62,6 @@
"AutoUnmonitorPreviouslyDownloadedBooksHelpText": "Books deleted from disk are automatically unmonitored in Readarr",
"Automatic": "Automatic",
"AutomaticAdd": "Automatic Add",
"AutomaticUpdatesDisabledDocker": "Automatic updates are not directly supported when using the Docker update mechanism. You will need to update the container image outside of {appName} or use a script",
"AutomaticallySwitchEdition": "Automatically Switch Edition",
"Backup": "Backup",
"BackupFolderHelpText": "Relative paths will be under Readarr's AppData directory",
@@ -152,9 +148,6 @@
"Connect": "Connect",
"ConnectSettings": "Connect Settings",
"ConnectSettingsSummary": "Notifications, connections to media servers/players and custom scripts",
"ConnectionLost": "Connection Lost",
"ConnectionLostReconnect": "{appName} will try to connect automatically, or you can click reload below.",
"ConnectionLostToBackend": "{appName} has lost its connection to the backend and will need to be reloaded to restore functionality.",
"Connections": "Connections",
"ConsoleLogLevel": "Console Log Level",
"Continuing": "Continuing",
@@ -166,10 +159,9 @@
"CopyUsingHardlinksHelpText": "Hardlinks allow Readarr to import seeding torrents to the the series folder without taking extra disk space or copying the entire contents of the file. Hardlinks will only work if the source and destination are on the same volume",
"CopyUsingHardlinksHelpTextWarning": "Occasionally, file locks may prevent renaming files that are being seeded. You may temporarily disable seeding and use Readarr's rename function as a work around.",
"CouldntFindAnyResultsForTerm": "Couldn't find any results for '{0}'",
"CountAuthorsSelected": "{selectedCount} author(s) selected",
"CountDownloadClientsSelected": "{selectedCount} download client(s) selected",
"CountImportListsSelected": "{selectedCount} import list(s) selected",
"CountIndexersSelected": "{selectedCount} indexer(s) selected",
"CountDownloadClientsSelected": "{0} download client(s) selected",
"CountImportListsSelected": "{0} import list(s) selected",
"CountIndexersSelected": "{0} indexer(s) selected",
"Country": "Country",
"CreateEmptyAuthorFolders": "Create empty author folders",
"CreateEmptyAuthorFoldersHelpText": "Create missing author folders during disk scan",
@@ -208,48 +200,48 @@
"DelayingDownloadUntilInterp": "Delaying download until {0} at {1}",
"Delete": "Delete",
"DeleteBackup": "Delete Backup",
"DeleteBackupMessageText": "Are you sure you want to delete the backup '{name}'?",
"DeleteBackupMessageText": "Are you sure you want to delete the backup '{0}'?",
"DeleteBookFile": "Delete Book File",
"DeleteBookFileMessageText": "Are you sure you want to delete {0}?",
"DeleteCondition": "Delete Condition",
"DeleteConditionMessageText": "Are you sure you want to delete condition '{name}'?",
"DeleteConditionMessageText": "Are you sure you want to delete condition '{0}'?",
"DeleteCustomFormat": "Delete Custom Format",
"DeleteCustomFormatMessageText": "Are you sure you want to delete the custom format '{name}'?",
"DeleteCustomFormatMessageText": "Are you sure you want to delete the custom format '{0}'?",
"DeleteDelayProfile": "Delete Delay Profile",
"DeleteDelayProfileMessageText": "Are you sure you want to delete this delay profile?",
"DeleteDownloadClient": "Delete Download Client",
"DeleteDownloadClientMessageText": "Are you sure you want to delete the download client '{name}'?",
"DeleteDownloadClientMessageText": "Are you sure you want to delete the download client '{0}'?",
"DeleteEmptyFolders": "Delete empty folders",
"DeleteEmptyFoldersHelpText": "Delete empty author folders during disk scan and when book files are deleted",
"DeleteFilesHelpText": "Delete the book files and author folder",
"DeleteFormat": "Delete Format",
"DeleteFormatMessageText": "Are you sure you want to delete format tag '{0}'?",
"DeleteFormatMessageText": "Are you sure you want to delete format tag {0} ?",
"DeleteImportList": "Delete Import List",
"DeleteImportListExclusion": "Delete Import List Exclusion",
"DeleteImportListExclusionMessageText": "Are you sure you want to delete this import list exclusion?",
"DeleteImportListMessageText": "Are you sure you want to delete the list '{name}'?",
"DeleteImportListMessageText": "Are you sure you want to delete the list '{0}'?",
"DeleteIndexer": "Delete Indexer",
"DeleteIndexerMessageText": "Are you sure you want to delete the indexer '{name}'?",
"DeleteIndexerMessageText": "Are you sure you want to delete the indexer '{0}'?",
"DeleteMetadataProfile": "Delete Metadata Profile",
"DeleteMetadataProfileMessageText": "Are you sure you want to delete the metadata profile '{name}'?",
"DeleteMetadataProfileMessageText": "Are you sure you want to delete the metadata profile '{0}'?",
"DeleteNotification": "Delete Notification",
"DeleteNotificationMessageText": "Are you sure you want to delete the notification '{name}'?",
"DeleteNotificationMessageText": "Are you sure you want to delete the notification '{0}'?",
"DeleteQualityProfile": "Delete Quality Profile",
"DeleteQualityProfileMessageText": "Are you sure you want to delete the quality profile '{name}'?",
"DeleteQualityProfileMessageText": "Are you sure you want to delete the quality profile '{0}'?",
"DeleteReleaseProfile": "Delete Release Profile",
"DeleteReleaseProfileMessageText": "Are you sure you want to delete this Release Profile?",
"DeleteRemotePathMapping": "Delete Remote Path Mapping",
"DeleteRemotePathMappingMessageText": "Are you sure you want to delete this remote path mapping?",
"DeleteRootFolder": "Delete Root Folder",
"DeleteRootFolderMessageText": "Are you sure you want to delete the root folder '{name}'?",
"DeleteRootFolderMessageText": "Are you sure you want to delete the root folder '{0}'?",
"DeleteSelectedBookFiles": "Delete Selected Book Files",
"DeleteSelectedBookFilesMessageText": "Are you sure you want to delete the selected book files?",
"DeleteSelectedDownloadClients": "Delete Download Client(s)",
"DeleteSelectedDownloadClientsMessageText": "Are you sure you want to delete {count} selected download client(s)?",
"DeleteSelectedDownloadClientsMessageText": "Are you sure you want to delete {0} selected download client(s)?",
"DeleteSelectedImportLists": "Delete Import List(s)",
"DeleteSelectedImportListsMessageText": "Are you sure you want to delete {count} selected import list(s)?",
"DeleteSelectedImportListsMessageText": "Are you sure you want to delete {0} selected import list(s)?",
"DeleteSelectedIndexers": "Delete Indexer(s)",
"DeleteSelectedIndexersMessageText": "Are you sure you want to delete {count} selected indexer(s)?",
"DeleteSelectedIndexersMessageText": "Are you sure you want to delete {0} selected indexer(s)?",
"DeleteTag": "Delete Tag",
"DeleteTagMessageText": "Are you sure you want to delete the tag '{0}'?",
"DestinationPath": "Destination Path",
@@ -579,14 +571,11 @@
"NoMinimumForAnyRuntime": "No minimum for any runtime",
"NoMissingItems": "No missing items",
"NoName": "Do not show name",
"NoResultsFound": "No results found",
"NoTagsHaveBeenAddedYet": "No tags have been added yet. Add tags to link authors with delay profiles, restrictions, or notifications. Click {0} to find out more about tags in Readarr.",
"NoUpdatesAreAvailable": "No updates are available",
"None": "None",
"NotAvailable": "Not Available",
"NotMonitored": "Not Monitored",
"NotificationStatusAllClientHealthCheckMessage": "All notifications are unavailable due to failures",
"NotificationStatusSingleClientHealthCheckMessage": "Notifications unavailable due to failures: {0}",
"NotificationTriggers": "Notification Triggers",
"OnApplicationUpdate": "On Application Update",
"OnApplicationUpdateHelpText": "On Application Update",
@@ -675,7 +664,6 @@
"ReadarrTags": "Readarr Tags",
"Real": "Real",
"Reason": "Reason",
"RecentChanges": "Recent Changes",
"RecycleBinCleanupDaysHelpText": "Set to 0 to disable automatic cleanup",
"RecycleBinCleanupDaysHelpTextWarning": "Files in the recycle bin older than the selected number of days will be cleaned up automatically",
"RecycleBinHelpText": "Book files will go here when deleted instead of being permanently deleted",
@@ -714,7 +702,6 @@
"RemotePathMappingCheckRemoteDownloadClient": "Remote download client {0} reported files in {1} but this directory does not appear to exist. Likely missing remote path mapping.",
"RemotePathMappingCheckWrongOSPath": "Remote download client {0} places downloads in {1} but this is not a valid {2} path. Review your remote path mappings and download client settings.",
"RemotePathMappings": "Remote Path Mappings",
"RemotePathMappingsInfo": "Remote Path Mappings are very rarely required, if {app} and your download client are on the same system it is better to match your paths. For more information see the [wiki]({wikiLink}).",
"Remove": "Remove",
"RemoveCompleted": "Remove Completed",
"RemoveCompletedDownloads": "Remove Completed Downloads",
@@ -857,7 +844,6 @@
"SkipSecondarySeriesBooks": "Skip secondary series books",
"Small": "Small",
"SmartReplace": "Smart Replace",
"SomeResultsAreHiddenByTheAppliedFilter": "Some results are hidden by the applied filter",
"SorryThatAuthorCannotBeFound": "Sorry, that author cannot be found.",
"SorryThatBookCannotBeFound": "Sorry, that book cannot be found.",
"Source": "Source",
@@ -1003,8 +989,6 @@
"WatchLibraryForChangesHelpText": "Rescan automatically when files change in a root folder",
"WatchRootFoldersForFileChanges": "Watch Root Folders for file changes",
"WeekColumnHeader": "Week Column Header",
"WhatsNew": "What's New?",
"WouldYouLikeToRestoreBackup": "Would you like to restore the backup '{name}'?",
"WriteAudioTags": "Tag Audio Files with Metadata",
"WriteAudioTagsScrub": "Scrub Existing Tags",
"WriteAudioTagsScrubHelp": "Remove existing tags from files, leaving only those added by Readarr.",

View File

@@ -1,6 +1,6 @@
{
"ApiKeyHelpTextWarning": "Requiere reiniciar para que surta efecto",
"DeleteRootFolderMessageText": "¿Está seguro de querer eliminar la carpeta raíz '{0}'?",
"DeleteRootFolderMessageText": "Seguro que quieres eliminar el indexer '{0}'?",
"LoadingBooksFailed": "La carga de los archivos ha fallado",
"ProxyUsernameHelpText": "Tienes que introducir tu nombre de usuario y contraseña sólo si son requeridos. Si no, déjalos vacios.",
"SslPortHelpTextWarning": "Requiere reiniciar para que surta efecto",
@@ -13,16 +13,16 @@
"Tags": "Etiquetas",
"60MinutesSixty": "60 Minutos: {0}",
"APIKey": "Clave API",
"About": "Acerca de",
"About": "Acerca",
"AddListExclusion": "Añadir Exclusión De Lista",
"AddingTag": "Añadir etiqueta",
"AgeWhenGrabbed": "Antigüedad (cuando se añadió)",
"AlreadyInYourLibrary": "Ya en tu biblioteca",
"AddingTag": "Añadiendo etiqueta",
"AgeWhenGrabbed": "Edad (cuando capturada)",
"AlreadyInYourLibrary": "Ya esta en tu librería",
"AlternateTitles": "Título alternativo",
"Analytics": "Analíticas",
"AnalyticsEnabledHelpText": "Envíe información anónima de uso y error a los servidores de Radarr. Esto incluye información sobre su navegador, qué páginas de Radarr WebUI utiliza, informes de errores, así como el sistema operativo y la versión en tiempo de ejecución. Usaremos esta información para priorizar funciones y correcciones de errores.",
"AnalyticsEnabledHelpTextWarning": "Requiere reiniciar para que surta efecto",
"AppDataDirectory": "Directorio AppData",
"AppDataDirectory": "Directorio de AppData",
"ApplyTags": "Aplicar Etiquetas",
"45MinutesFourtyFive": "45 Minutos: {0}",
"Authentication": "Autenticación",
@@ -32,11 +32,11 @@
"AutoUnmonitorPreviouslyDownloadedBooksHelpText": "Las películas eliminadas del disco son automáticamente desmonitorizadas en Radarr",
"Automatic": "Automático",
"BackupFolderHelpText": "Las rutas relativas estarán en el directorio AppData de Radarr",
"BackupNow": "Hacer copia de seguridad ahora",
"BackupRetentionHelpText": "Las copias de seguridad automáticas anteriores al período de retención serán borradas automáticamente",
"BackupNow": "Backup Ahora",
"BackupRetentionHelpText": "Backups automáticos anteriores al período de retención serán borrados automáticamente",
"Backups": "Copias de seguridad",
"BindAddress": "Dirección de Ligado",
"BindAddressHelpText": "Dirección IP4 válida, localhost o '*' para todas las interfaces",
"BindAddressHelpText": "Dirección IP4 válida o '*' para todas las interfaces",
"BindAddressHelpTextWarning": "Requiere reiniciar para que surta efecto",
"BookIsDownloadingInterp": "La película está descargando - {0}% {1}",
"Branch": "Rama",
@@ -216,7 +216,7 @@
"MustNotContain": "No Debe Contener",
"Name": "Nombre",
"NamingSettings": "Ajustes de Renombrado",
"New": "Nuevo",
"New": "Nueva",
"NoBackupsAreAvailable": "No hay copias de seguridad disponibles",
"NoHistory": "Sin historia",
"NoLeaveIt": "No, Déjalo",
@@ -300,7 +300,7 @@
"RequiredPlaceHolder": "Añadir nueva restricción",
"RescanAfterRefreshHelpTextWarning": "Radarr no detectará los cambios automáticamente en los ficheros si no se ajusta a 'Siempre'",
"RescanAuthorFolderAfterRefresh": "Reescanear la Carpeta de Películas después de Actualizar",
"Reset": "Reiniciar",
"Reset": "Reajustar",
"ResetAPIKey": "Reajustar API",
"ResetAPIKeyMessageText": "¿Está seguro de que desea restablecer su clave API?",
"Restart": "Reiniciar",
@@ -348,7 +348,7 @@
"SkipFreeSpaceCheckWhenImportingHelpText": "Usar cuando Radarr no pueda detectar el espacio disponible en la carpeta de películas",
"SorryThatAuthorCannotBeFound": "Lo siento, no he encontrado esa película.",
"SorryThatBookCannotBeFound": "Lo siento, no he encontrado esa película.",
"Source": "Fuente",
"Source": "Origen",
"SourcePath": "Ruta de Origen",
"SslCertPasswordHelpText": "Contraseña para el archivo pfx",
"SslCertPasswordHelpTextWarning": "Requiere reiniciar para que surta efecto",
@@ -416,7 +416,7 @@
"UnableToLoadTheCalendar": "No se ha podido cargar el calendario",
"UnableToLoadUISettings": "No se han podido cargar los ajustes de UI",
"Ungroup": "Desagrupar",
"Unmonitored": "Sin monitorizar",
"Unmonitored": "No monitoreadas",
"UnmonitoredHelpText": "Incluir las peliculas no monitoreadas en el feed de iCal",
"UpdateAll": "Actualizar Todo",
"UpdateAutomaticallyHelpText": "Descargar e instalar actualizaciones automáticamente. Se podrán instalar desde Sistema: Actualizaciones también",
@@ -437,7 +437,7 @@
"Version": "Versión",
"WeekColumnHeader": "Encabezado de la columna semanal",
"Year": "Año",
"YesCancel": "Sí, Cancelar",
"YesCancel": "Si, cancelar",
"20MinutesTwenty": "20 Minutos: {0}",
"DownloadClientCheckDownloadingToRoot": "El cliente de descargas {0} coloca las descargas en la carpeta raíz {1}. No debe descargar a una carpeta raíz.",
"MaintenanceRelease": "Lanzamiento de mantenimiento",
@@ -457,7 +457,7 @@
"TheAuthorFolderAndAllOfItsContentWillBeDeleted": "Se eliminará la carpeta de películas '{0}' y todo su contenido.",
"Component": "Componente",
"RemoveFromBlocklist": "Eliminar de lista de bloqueados",
"Time": "Tiempo",
"Time": "Fecha",
"UnableToLoadBlocklist": "No se han podido cargar las bloqueadas",
"Level": "Nivel",
"ReleaseBranchCheckOfficialBranchMessage": "Las versión {0} no es una versión válida de Radarr, no recibirás actualizaciones",
@@ -467,7 +467,7 @@
"SelectAll": "Seleccionar Todas",
"SelectedCountBooksSelectedInterp": "{0} Película(s) Seleccionada(s)",
"ThisCannotBeCancelled": "Esto no puede ser cancelado una vez iniciado sin deshabilitar todos sus indexadores.",
"All": "Todo",
"All": "Todas",
"RescanAfterRefreshHelpText": "Reescanear la carpeta de películas después de actualizar la película",
"ShowUnknownAuthorItems": "Mostrar Elementos Desconocidos",
"UnselectAll": "Deseleccionar Todo",
@@ -492,7 +492,7 @@
"Yesterday": "Ayer",
"UpdateAvailable": "La nueva actualización está disponible",
"Duration": "Duración",
"AppDataLocationHealthCheckMessage": "No será posible actualizar para prevenir la eliminación de AppData al Actualizar",
"AppDataLocationHealthCheckMessage": "No será posible actualizar para prevenir que AppData se borre durante la actualización",
"Lists": "Listas",
"SizeLimit": "Tamaño límite",
"IndexerJackettAll": "Indexadores que utilizan el Endpoint Jackett 'all' no están soportados: {0}",
@@ -550,7 +550,7 @@
"ProxyCheckBadRequestMessage": "Fallo al comprobar el proxy. StatusCode: {0}",
"ProxyCheckFailedToTestMessage": "Fallo al comprobar el proxy: {0}",
"QualitySettingsSummary": "Tamaños de calidad y nombrado",
"Queued": "Encolado",
"Queued": "En Cola",
"QueueIsEmpty": "La cola está vacía",
"RefreshAndScan": "Actualizar y Escanear",
"RestartReloadNote": "Nota: Radarr se reiniciará y recargará automáticamente la IU durante el proceso de restauración.",
@@ -582,7 +582,7 @@
"FileWasDeletedByUpgrade": "Se eliminó el archivo para importar una actualización",
"IndexersSettingsSummary": "Indexers y restricciones de lanzamientos",
"RestartRequiredHelpTextWarning": "Requiere reiniciar para que surta efecto",
"AddList": "Añadir Lista",
"AddList": "Añadir lista",
"RenameFiles": "Renombrar Archivos",
"Test": "Test",
"InstanceName": "Nombre de Instancia",
@@ -650,19 +650,19 @@
"NoEventsFound": "No se encontraron eventos",
"ApplyTagsHelpTextHowToApplyAuthors": "Cómo añadir etiquetas a las películas seleccionadas",
"DeleteSelectedIndexersMessageText": "Seguro que quieres eliminar el indexer '{0}'?",
"Yes": "",
"Yes": "si",
"RedownloadFailed": "La descarga ha fallado",
"RemoveCompleted": "Eliminación completada",
"RemoveDownloadsAlert": "Los ajustes de eliminación se han trasladado a los ajustes individuales del cliente de descarga en la tabla anterior.",
"RemoveFailed": "La eliminación falló",
"ApplyTagsHelpTextAdd": "Añadir: Añadir a las etiquetas la lista existente de etiquetas",
"ApplyTagsHelpTextHowToApplyDownloadClients": "Cómo añadir etiquetas a los clientes de descargas seleccionados",
"ApplyTagsHelpTextHowToApplyImportLists": "Cómo añadir etiquetas a las listas de importación seleccionadas",
"ApplyTagsHelpTextHowToApplyIndexers": "Cómo añadir etiquetas a los indexadores seleccionados",
"ApplyTagsHelpTextHowToApplyDownloadClients": "Cómo añadir etiquetas a las películas seleccionadas",
"ApplyTagsHelpTextHowToApplyImportLists": "Cómo añadir etiquetas a las películas seleccionadas",
"ApplyTagsHelpTextHowToApplyIndexers": "Cómo añadir etiquetas a las películas seleccionadas",
"ApplyTagsHelpTextRemove": "Eliminar: Eliminar las etiquetas introducidas",
"ApplyTagsHelpTextReplace": "Reemplazar: Reemplazar las etiquetas con las etiquetas introducidas (no introducir etiquetas para eliminar todas las etiquetas)",
"DeleteSelectedDownloadClients": "Borrar Gestor de Descargas",
"DeleteSelectedDownloadClientsMessageText": "¿Está seguro de querer eliminar {0} cliente(s) de descarga seleccionado(s)?",
"DeleteSelectedDownloadClientsMessageText": "Seguro que quieres eliminar el indexer '{0}'?",
"DeleteSelectedImportListsMessageText": "Seguro que quieres eliminar el indexer '{0}'?",
"DeleteSelectedIndexers": "Borrar Indexer",
"DownloadClientTagHelpText": "Solo utilizar este indexador para películas que coincidan con al menos una etiqueta. Déjelo en blanco para utilizarlo con todas las películas.",
@@ -670,63 +670,5 @@
"No": "No",
"NoChange": "Sin Cambio",
"RemovingTag": "Eliminando etiqueta",
"SetTags": "Poner Etiquetas",
"DeleteRemotePathMappingMessageText": "¿Está seguro de querer eliminar esta asignación de ruta remota?",
"ApplicationURL": "URL de la aplicación",
"ApplicationUrlHelpText": "La URL externa de la aplicación incluyendo http(s)://, puerto y URL base",
"AutomaticAdd": "Añadir Automáticamente",
"AutoAdd": "Añadir Automáticamente",
"EditSelectedIndexers": "Editar Indexadores Seleccionados",
"DeleteRootFolder": "Eliminar Carpeta Raíz",
"Clone": "Clonar",
"CloneCondition": "Clonar Condición",
"ApplyChanges": "Aplicar Cambios",
"CountDownloadClientsSelected": "{0} cliente(s) de descarga seleccionado(s)",
"CountImportListsSelected": "{0} lista(s) de importación seleccionada(s)",
"CountIndexersSelected": "{0} indexador(es) seleccionado(s)",
"DeleteCondition": "Eliminar Condición",
"DeleteSelectedImportLists": "Eliminar Lista(s) de Importación",
"EditSelectedDownloadClients": "Editar Clientes de Descarga Seleccionados",
"EditSelectedImportLists": "Editar Listas de Importación Seleccionadas",
"Implementation": "Implementación",
"ApiKeyValidationHealthCheckMessage": "Actualice su clave de API para que tenga al menos {0} carácteres. Puede hacerlo en los ajustes o en el archivo de configuración",
"ListRefreshInterval": "Intervalo de Refresco de Lista",
"ListWillRefreshEveryInterp": "La lista será refrescada cada {0}",
"Activity": "Actividad",
"Location": "Ubicación",
"Ui": "UI",
"AddNew": "Añadir Nuevo",
"Backup": "Copia de seguridad",
"ManageClients": "Gestionar Clientes",
"ManageDownloadClients": "Gestionar Clientes de Descarga",
"ManageIndexers": "Gestionar Indexadores",
"ManageLists": "Gestionar Listas",
"System": "Sistema",
"TotalSpace": "Espacio Total",
"IndexerDownloadClientHealthCheckMessage": "Indexadores con clientes de descarga inválidos: {0}.",
"ManageImportLists": "Gestionar Listas de Importación",
"ConnectionLostToBackend": "Radarr ha perdido su conexión con el backend y tendrá que ser recargado para recuperar su funcionalidad.",
"NotificationStatusSingleClientHealthCheckMessage": "Listas no disponibles debido a errores: {0}",
"NotificationStatusAllClientHealthCheckMessage": "Las listas no están disponibles debido a errores",
"ReleaseProfiles": "perfil de lanzamiento",
"Small": "Pequeña",
"DeleteImportList": "Eliminar Lista(s) de Importación",
"Large": "Grande",
"Library": "Biblioteca",
"SomeResultsAreHiddenByTheAppliedFilter": "Algunos resultados están ocultos por el filtro aplicado",
"FreeSpace": "Espacio Libre",
"LastDuration": "Duración",
"LastExecution": "Última ejecución",
"LastWriteTime": "Última Fecha de Escritura",
"ConnectionLost": "Conexión perdida",
"ConnectionLostReconnect": "Radarr intentará conectarse automáticamente, o haz clic en el botón de recarga abajo.",
"NextExecution": "Siguiente ejecución",
"NoResultsFound": "No se han encontrado resultados",
"RecentChanges": "Cambios recientes",
"WhatsNew": "¿Qué hay de nuevo?",
"Loading": "Cargando",
"Events": "Eventos",
"Medium": "Medio",
"AllResultsAreHiddenByTheAppliedFilter": "Todos los resultados están ocultos por el filtro aplicado",
"CatalogNumber": "número de catálogo"
"SetTags": "Poner Etiquetas"
}

View File

@@ -852,32 +852,5 @@
"RemovingTag": "Tunniste poistetaan",
"RemoveCompleted": "Poista valmistuneet",
"RemoveDownloadsAlert": "Poistoasetukset on siirretty yllä olevassa taulukossa yksittäisten lataustyökalujen alle.",
"SetTags": "Tunnisteiden määritys",
"ConnectionLostToBackend": "Radarr on menettänyt yhteyden taustajärjestelmään ja sivu on päivitettävä toiminnallisuuden palauttamiseksi.",
"NotificationStatusAllClientHealthCheckMessage": "Sovellukset eivät ole käytettävissä virheiden vuoksi",
"NotificationStatusSingleClientHealthCheckMessage": "Sovellukset eivät ole käytettävissä virheiden vuoksi: {0}",
"System": "Järjestelmä",
"TotalSpace": "Kokonaistila",
"Ui": "Käyttöliittymä",
"Library": "Kirjasto",
"Medium": "Keskitaso",
"Small": "Pieni",
"AllResultsAreHiddenByTheAppliedFilter": "Kaikki tulokset on piilotettu aktiivisen suodattimen johdosta.",
"Events": "Tapahtumat",
"FreeSpace": "Vapaa tila",
"ConnectionLost": "Yhteys on katkennut",
"ConnectionLostReconnect": "Radarr pyrkii muodostamaan yhteyden automaattisesti tai voit painaa alta \"Lataa uudelleen\".",
"RecentChanges": "Viimeaikaiset muutokset",
"WhatsNew": "Mikä on uutta?",
"Large": "Suuri",
"LastDuration": "Edellinen kesto",
"LastExecution": "Edellinen suoritus",
"LastWriteTime": "Viimeisin kirjoitusaika",
"Location": "Sijainti",
"NoResultsFound": "Ei tuloksia",
"SomeResultsAreHiddenByTheAppliedFilter": "Joitakin tuloksia piilottaa käytetty suodatin",
"Activity": "Tapahtumat",
"AddNew": "Lisää uusi",
"Backup": "Varmuuskopio",
"NextExecution": "Seuraava suoritus"
"SetTags": "Tunnisteiden määritys"
}

View File

@@ -763,32 +763,5 @@
"SetTags": "Définir Tags",
"CountDownloadClientsSelected": "{0} client(s) de téléchargement sélectionné(s)",
"EditSelectedDownloadClients": "Modifier les clients de téléchargement sélectionnés",
"EditSelectedIndexers": "Modifier les indexeurs sélectionnés",
"ConnectionLostReconnect": "Radarr essaiera de se connecter automatiquement, ou vous pouvez cliquer sur \"Recharger\" en bas.",
"NotificationStatusAllClientHealthCheckMessage": "Toutes les applications sont indisponibles en raison de dysfonctionnements",
"NotificationStatusSingleClientHealthCheckMessage": "Applications indisponibles en raison de dysfonctionnements : {0}",
"SomeResultsAreHiddenByTheAppliedFilter": "Tous les résultats ont été dissimulés par le filtre actuellement appliqué",
"ConnectionLost": "Connexion perdue",
"ConnectionLostToBackend": "Radarr a perdu sa connexion au backend et devra être rechargé pour fonctionner à nouveau.",
"RecentChanges": "Changements récents",
"System": "Système",
"WhatsNew": "Quoi de neuf ?",
"AllResultsAreHiddenByTheAppliedFilter": "Tous les résultats ont été dissimulés par le filtre actuellement appliqué",
"Location": "Emplacement",
"NoResultsFound": "Aucun résultat trouvé",
"Events": "Événements",
"FreeSpace": "Espace libre",
"Large": "Grand",
"LastDuration": "Dernière durée",
"LastExecution": "Dernière exécution",
"Library": "Bibliothèque",
"LastWriteTime": "Heure de la dernière écriture",
"Medium": "Moyen",
"NextExecution": "Prochaine exécution",
"Small": "Petit",
"TotalSpace": "Espace total",
"Ui": "UI",
"Activity": "Activité",
"AddNew": "Ajouter un nouveau",
"Backup": "Sauvegarde"
"EditSelectedIndexers": "Modifier les indexeurs sélectionnés"
}

View File

@@ -629,32 +629,5 @@
"ExistingTag": "תג קיים",
"RemovingTag": "הסרת התג",
"SetTags": "הגדר תגים",
"Yes": "כן",
"Events": "אירועים",
"RecentChanges": "שינויים אחרונים",
"WhatsNew": "מה חדש?",
"NotificationStatusAllClientHealthCheckMessage": "כל הרשימות אינן זמינות בגלל כשלים",
"NotificationStatusSingleClientHealthCheckMessage": "רשימות לא זמינות בגלל כשלים: {0}",
"NoResultsFound": "לא נמצאו תוצאות",
"Ui": "ממשק משתמש",
"CatalogNumber": "מספר קטלוג",
"ConnectionLost": "החיבור אבד",
"ConnectionLostReconnect": "Radarr ינסה להתחבר אוטומטית, או שתלחץ על טען מחדש למטה.",
"AllResultsAreHiddenByTheAppliedFilter": "כל התוצאות מוסתרות על ידי המסנן שהוחל",
"FreeSpace": "מקום פנוי",
"LastExecution": "ביצוע אחרון",
"LastWriteTime": "זמן כתיבה אחרון",
"NextExecution": "הביצוע הבא",
"SomeResultsAreHiddenByTheAppliedFilter": "חלק מהתוצאות מוסתרות על ידי המסנן שהוחל",
"Activity": "פעילות",
"AddNew": "הוסף חדש",
"Backup": "גיבוי",
"Large": "גָדוֹל",
"LastDuration": "lastDuration",
"Location": "מקום",
"Medium": "בינוני",
"Small": "קָטָן",
"System": "מערכת",
"Theme": "ערכת נושא",
"TotalSpace": "השטח הכולל"
"Yes": "כן"
}

View File

@@ -948,33 +948,5 @@
"No": "Nem",
"NoChange": "Nincs változtatás",
"RemoveCompletedDownloads": "Befejezett letöltések eltávolítása",
"RemovingTag": "Címke eltávolítása",
"NextExecution": "Következő végrehajtás",
"NotificationStatusAllClientHealthCheckMessage": "Összes alkalmazás elérhetetlen hiba miatt",
"NotificationStatusSingleClientHealthCheckMessage": "Az alkalmazás nem áll rendelkezésre az alábbi hibák miatt: {0}",
"Small": "kicsi",
"SkipRedownloadHelpText": "Megakadályozza, hogy a Lidarr megpróbálja letölteni az eltávolított elemek alternatív kiadásait",
"Events": "Események",
"FreeSpace": "Szabad Tárhely",
"NoResultsFound": "Nem eredményezett találatot",
"SomeResultsAreHiddenByTheAppliedFilter": "Néhány találat nem látható az alkalmazott szűrők miatt",
"System": "Rendszer",
"TotalSpace": "Összes szabad hely",
"Ui": "Felület",
"ConnectionLost": "Kapcsolódás Elveszett",
"ConnectionLostReconnect": "A Radarr megpróbál automatikusan csatlakozni, vagy kattints a frissítés gombra.",
"ConnectionLostToBackend": "A Radarr elvesztette kapcsolatát a háttérrendszerrel, a funkciók helyreállításához frissíts.",
"RecentChanges": "Friss változtatások",
"WhatsNew": "Mi az újdonság?",
"Large": "Óriási",
"LastDuration": "Utolsó időtartam",
"LastExecution": "Utolsó végrehajtás",
"LastWriteTime": "Utolsó írási idő",
"Library": "Könyvtár",
"Location": "Lokáció",
"AllResultsAreHiddenByTheAppliedFilter": "Az alkalmazott szűrők miatt, az összes keresési eredmény rejtve marad",
"Activity": "Aktivitás",
"AddNew": "Új hozzáadása",
"Backup": "Biztonsági Mentés",
"Medium": "Közepes"
"RemovingTag": "Címke eltávolítása"
}

View File

@@ -6,7 +6,7 @@
"APIKey": "Chiave API",
"About": "Info",
"AddListExclusion": "Aggiungi Lista Esclusioni",
"AddingTag": "Aggiungendo etichetta",
"AddingTag": "Aggiungi etichetta",
"Fixed": "Fissato",
"Local": "Locale",
"Remove": "Rimuovi",
@@ -40,7 +40,7 @@
"BackupFolderHelpText": "I percorsi relativi saranno nella cartella AppData di Readarr",
"BackupNow": "Esegui backup ora",
"BackupRetentionHelpText": "I backup automatici più vecchi del periodo di conservazione verranno eliminati automaticamente",
"Backups": "Backups",
"Backups": "I Backup",
"BindAddress": "Indirizzo di Bind",
"BindAddressHelpText": "Indirizzo IP valido, localhost o '*' per tutte le interfacce di rete",
"BindAddressHelpTextWarning": "Richiede il riavvio per avere effetto",
@@ -717,12 +717,5 @@
"RedownloadFailed": "Download fallito",
"RemoveSelectedItems": "Rimuovi elementi selezionati",
"RemovingTag": "Sto eliminando il tag",
"SetTags": "Imposta Etichette",
"Activity": "Attività",
"AutoAdd": "Aggiungi Automaticamente",
"ApplyChanges": "Applica Cambiamenti",
"ApiKeyValidationHealthCheckMessage": "Aggiorna la tua chiave API in modo che abbia una lunghezza di almeno {0} caratteri. Puoi farlo dalle impostazioni o dal file di configurazione",
"AddNew": "Aggiungi Nuovo",
"AutomaticAdd": "Aggiungi Automaticamente",
"Backup": "Backup"
"SetTags": "Imposta Etichette"
}

View File

@@ -601,30 +601,5 @@
"RedownloadFailed": "ダウンロードに失敗しました",
"ApplyTagsHelpTextHowToApplyDownloadClients": "選択した映画にタグを適用する方法",
"ApplyTagsHelpTextAdd": "追加:既存のタグリストにタグを追加します",
"DeleteSelectedDownloadClients": "ダウンロードクライアントを削除する",
"ConnectionLost": "接続切断",
"ConnectionLostReconnect": "Radarrは自動的に接続を試みます。または、下の[再読み込み]をクリックしてください。",
"NotificationStatusAllClientHealthCheckMessage": "障害のため、すべてのリストを利用できません",
"NotificationStatusSingleClientHealthCheckMessage": "失敗のため利用できないリスト:{0}",
"System": "システム",
"TotalSpace": "総スペース",
"Large": "大",
"LastDuration": "lastDuration",
"LastExecution": "最後の実行",
"LastWriteTime": "最終書き込み時間",
"Location": "ロケーション",
"NextExecution": "次の実行",
"Small": "小さい",
"SomeResultsAreHiddenByTheAppliedFilter": "一部の結果は、適用されたフィルターによって非表示になります",
"Ui": "UI",
"RecentChanges": "最近の変化",
"WhatsNew": "新着情報?",
"AllResultsAreHiddenByTheAppliedFilter": "すべての結果は、適用されたフィルターによって非表示になります",
"Backup": "バックアップ",
"Events": "イベント",
"FreeSpace": "フリースペース",
"Medium": "中",
"NoResultsFound": "結果が見つかりません",
"Activity": "アクティビティ",
"AddNew": "新しく追加する"
"DeleteSelectedDownloadClients": "ダウンロードクライアントを削除する"
}

View File

@@ -596,26 +596,5 @@
"RemovingTag": "태그 제거",
"SetTags": "태그 설정",
"Yes": "예",
"RedownloadFailed": "다운로드 실패함",
"LastWriteTime": "마지막 쓰기 시간",
"Location": "위치",
"ConnectionLostReconnect": "Radarr가 자동으로 연결을 시도하거나 아래에서 새로고침을 클릭할 수 있습니다.",
"ConnectionLostToBackend": "Radarr는 백엔드와의 연결이 끊어졌으며 기능을 복원하려면 다시 로딩해야 합니다.",
"NotificationStatusAllClientHealthCheckMessage": "실패로 인해 모든 목록을 사용할 수 없습니다.",
"NotificationStatusSingleClientHealthCheckMessage": "실패로 인해 사용할 수없는 목록 : {0}",
"TotalSpace": "총 공간",
"Ui": "UI",
"FreeSpace": "여유 공간",
"NextExecution": "다음 실행",
"SomeResultsAreHiddenByTheAppliedFilter": "적용된 필터에 의해 모든 결과가 숨겨집니다.",
"System": "체계",
"Medium": "매질",
"ConnectionLost": "연결이 끊어졌습니다.",
"AllResultsAreHiddenByTheAppliedFilter": "적용된 필터에 의해 모든 결과가 숨겨집니다.",
"Events": "이벤트",
"LastDuration": "lastDuration",
"LastExecution": "마지막 실행",
"Activity": "활동",
"AddNew": "새로 추가",
"Backup": "백업"
"RedownloadFailed": "다운로드 실패함"
}

View File

@@ -650,31 +650,5 @@
"RemoveFailed": "Usuń nieudane",
"Yes": "tak",
"ApplyChanges": "Zastosuj zmiany",
"ApiKeyValidationHealthCheckMessage": "Zaktualizuj swój klucz API aby był długi na co najmniej {0} znaków. Możesz to zrobić poprzez ustawienia lub plik konfiguracyjny",
"ConnectionLostToBackend": "Radarr utracił połączenie z silnikiem programu, aby przywrócić funkcjonalność musi zostać zrestartowany.",
"Large": "Duży",
"LastDuration": "Ostatni czas trwania",
"LastExecution": "Ostatnia egzekucja",
"LastWriteTime": "Czas ostatniego zapisu",
"Location": "Lokalizacja",
"NoResultsFound": "Nie znaleziono wyników",
"SomeResultsAreHiddenByTheAppliedFilter": "Niektóre wyniki są ukrywane przez zastosowany filtr",
"Events": "Wydarzenia",
"NotificationStatusAllClientHealthCheckMessage": "Wszystkie listy są niedostępne z powodu błędów",
"NotificationStatusSingleClientHealthCheckMessage": "Listy niedostępne z powodu błędów: {0}",
"System": "System",
"TotalSpace": "Powierzchnia całkowita",
"Ui": "UI",
"Medium": "Średni",
"Small": "Mały",
"ConnectionLost": "Utracono połączenie",
"ConnectionLostReconnect": "Radarr spróbuje połączyć się automatycznie lub możesz kliknąć przycisk przeładuj poniżej.",
"RecentChanges": "Ostatnie zmiany",
"WhatsNew": "Co nowego?",
"NextExecution": "Następne wykonanie",
"FreeSpace": "Wolna przestrzeń",
"Activity": "Aktywność",
"AddNew": "Dodaj nowy",
"Backup": "Kopia zapasowa",
"AllResultsAreHiddenByTheAppliedFilter": "Wszystkie wyniki są ukrywane przez zastosowany filtr"
"ApiKeyValidationHealthCheckMessage": "Zaktualizuj swój klucz API aby był długi na co najmniej {0} znaków. Możesz to zrobić poprzez ustawienia lub plik konfiguracyjny"
}

View File

@@ -14,7 +14,7 @@
"45MinutesFourtyFive": "45 Minutos: {0}",
"60MinutesSixty": "60 Minutos: {0}",
"APIKey": "Chave API",
"AgeWhenGrabbed": "Idade (quando baixado)",
"AgeWhenGrabbed": "Tempo de vida (quando obtido)",
"ApiKeyHelpTextWarning": "Requer reinício para ter efeito",
"LoadingBooksFailed": "Falha ao carregar livros",
"Logs": "Registros",
@@ -37,14 +37,14 @@
"AutoUnmonitorPreviouslyDownloadedBooksHelpText": "Livros excluídos do disco deixam de ser monitorados no Readarr automaticamente",
"Automatic": "Automático",
"BackupFolderHelpText": "Os caminhos relativos estarão no diretório AppData do Readarr",
"BackupNow": "Fazer backup agora",
"BackupNow": "Fazer Backup Agora",
"BackupRetentionHelpText": "Backups automáticos anteriores ao período de retenção serão limpos automaticamente",
"Backups": "Backups",
"BindAddress": "Fixar Endereço",
"BindAddressHelpText": "Endereço IP válido, localhost ou '*' para todas as interfaces",
"BindAddressHelpTextWarning": "Requer reiniciar para ter efeito",
"BookIsDownloading": "O livro está baixando",
"DiskSpace": "Espaço em disco",
"DiskSpace": "Espaço em Disco",
"Docker": "Docker",
"DownloadClient": "Cliente de Download",
"DownloadClientSettings": "Configurações do Cliente de Download",
@@ -59,7 +59,7 @@
"Enable": "Habilitar",
"GrabRelease": "Capturar Versão",
"GrabReleaseMessageText": "O Readarr não conseguiu determinar a qual autor e livro esse lançamento está relacionado. O Readarr pode não conseguir importar automaticamente este lançamento. Quer obter \"{0}\"?",
"GrabSelected": "Obter Selecionado",
"GrabSelected": "Obter selecionado",
"Group": "Grupo",
"HasPendingChangesNoChanges": "Sem alterações",
"HasPendingChangesSaveChanges": "Salvar alterações",
@@ -100,7 +100,7 @@
"CreateEmptyAuthorFoldersHelpText": "Criar pastas de autor ausente durante a verificação do disco",
"CreateGroup": "Criar grupo",
"CutoffHelpText": "Assim que esta qualidade for alcançada, o Readarr não baixará mais livros",
"CutoffUnmet": "Corte não atendido",
"CutoffUnmet": "Corte não alcançado",
"DBMigration": "Migração de banco de dados",
"Dates": "Datas",
"DelayProfile": "Perfil de Atraso",
@@ -108,34 +108,34 @@
"DelayingDownloadUntilInterp": "Atrasando o download até {0} às {1}",
"Delete": "Excluir",
"DeleteBackup": "Excluir Backup",
"DeleteBackupMessageText": "Tem certeza de que deseja excluir o backup '{name}'?",
"DeleteBackupMessageText": "Tem certeza que deseja excluir o backup \"{0}\"?",
"DeleteDelayProfile": "Excluir Perfil de Atraso",
"DeleteDelayProfileMessageText": "Tem certeza de que deseja excluir este perfil de atraso?",
"DeleteDownloadClient": "Excluir Cliente de Download",
"DeleteDownloadClientMessageText": "Tem certeza de que deseja excluir o cliente de download '{name}'?",
"DeleteDownloadClientMessageText": "Tem certeza que deseja excluir o cliente de download \"{0}\"?",
"DeleteEmptyFolders": "Excluir pastas vazias",
"DeleteEmptyFoldersHelpText": "Excluir pastas de autor vazias durante a verificação do disco e quando os arquivos de livros forem excluídos",
"DeleteImportListExclusion": "Excluir Exclusão da Lista de Importação",
"DeleteImportListExclusionMessageText": "Tem certeza de que deseja excluir esta exclusão da lista de importação?",
"DeleteImportListMessageText": "Tem certeza de que deseja excluir a lista '{name}'?",
"DeleteImportListMessageText": "Tem certeza de que deseja excluir a lista \"{0}\"?",
"DeleteIndexer": "Excluir Indexador",
"DeleteIndexerMessageText": "Tem certeza de que deseja excluir o indexador '{name}'?",
"DeleteMetadataProfileMessageText": "Tem certeza de que deseja excluir o perfil de metadados '{name}'?",
"DeleteIndexerMessageText": "Tem certeza de que deseja excluir o indexador \"{0}\"?",
"DeleteMetadataProfileMessageText": "Tem certeza que deseja excluir o perfil de metadados \"{0}\"?",
"DeleteNotification": "Excluir Notificação",
"DeleteNotificationMessageText": "Tem certeza de que deseja excluir o perfil de metadados '{name}'?",
"DeleteNotificationMessageText": "Tem certeza de que deseja excluir a notificação \"{0}\"?",
"DeleteQualityProfile": "Excluir Perfil de Qualidade",
"DeleteQualityProfileMessageText": "Tem certeza de que deseja excluir o perfil de qualidade '{name}'?",
"DeleteQualityProfileMessageText": "Tem certeza que deseja excluir o perfil de qualidade \"{0}\"?",
"DeleteReleaseProfile": "Excluir Perfil de Lançamento",
"DeleteReleaseProfileMessageText": "Tem certeza de que deseja excluir este Perfil de Lançamento?",
"DeleteRootFolderMessageText": "Tem certeza de que deseja excluir a pasta raiz '{name}'?",
"DeleteRootFolderMessageText": "Tem certeza de que deseja excluir a pasta raiz '{0}'?",
"DeleteSelectedBookFiles": "Excluir arquivos do livro selecionado",
"DeleteSelectedBookFilesMessageText": "Tem certeza de que deseja excluir os arquivos do livro selecionado?",
"DeleteTag": "Excluir tag",
"DeleteTagMessageText": "Tem certeza de que deseja excluir a tag \"{0}\"?",
"DestinationPath": "Caminho de Destino",
"DestinationPath": "Caminho de destino",
"DetailedProgressBarHelpText": "Mostrar texto em barra de progresso",
"EnableAutomaticAdd": "Habilitar Adição Automática",
"EnableAutomaticSearch": "Ativar a pesquisa automática",
"EnableAutomaticSearch": "Ativar pesquisa automática",
"EnableColorImpairedMode": "Habilitar Modo para Deficientes Visuais",
"EnableColorImpairedModeHelpText": "Estilo alterado para permitir que usuários com deficiência de cor distingam melhor as informações codificadas por cores",
"EnableCompletedDownloadHandlingHelpText": "Importar automaticamente downloads concluídos do cliente de download",
@@ -163,12 +163,12 @@
"ForMoreInformationOnTheIndividualDownloadClientsClickOnTheInfoButtons": "Para obter mais informações sobre os clientes de download individuais, clique nos botões de informações.",
"ForMoreInformationOnTheIndividualIndexersClickOnTheInfoButtons": "Para saber mais sobre cada indexador, clique nos botões de informações.",
"ForMoreInformationOnTheIndividualListsClickOnTheInfoButtons": "Para saber mais sobre cada lista, clique nos botões de informação.",
"GeneralSettings": "Configurações gerais",
"GeneralSettings": "Configurações Gerais",
"Global": "Global",
"GoToInterp": "Ir para {0}",
"Grab": "Obter",
"GrabID": "Obter ID",
"IconForCutoffUnmet": "Ícone para Corte Não Atendido",
"IconForCutoffUnmet": "Ícone para Limite não atingido",
"IconTooltip": "Agendado",
"IgnoredAddresses": "Endereços Ignorados",
"IgnoredHelpText": "O lançamento será rejeitado se contiver um ou mais desses termos (não diferencia maiúsculas de minúsculas)",
@@ -179,7 +179,7 @@
"Mode": "Modo",
"ImportExtraFilesHelpText": "Importar arquivos adicionais correspondentes (legendas, nfo, etc.) após importar um arquivo de livro",
"ImportFailedInterp": "Falha na importação: {0}",
"ImportedTo": "Importado Para",
"ImportedTo": "Importado para",
"Importing": "Importando",
"IncludeHealthWarningsHelpText": "Incluir avisos de integridade",
"IncludeUnknownAuthorItemsHelpText": "Mostrar itens sem autor na fila, isso pode incluir autores removidos, livros ou qualquer outra coisa na categoria de Readarr",
@@ -203,7 +203,7 @@
"LongDateFormat": "Formato de Data Longa",
"MIA": "Desaparecidos",
"ManualImport": "Importação manual",
"MarkAsFailed": "Marcar como Falha",
"MarkAsFailed": "Marcar como falhado",
"MarkAsFailedMessageText": "Tem certeza que deseja marcar \"{0}\" como falhado?",
"MaximumLimits": "Limites Máximos",
"MaximumSize": "Tamanho Máximo",
@@ -225,11 +225,11 @@
"New": "Novo",
"NoBackupsAreAvailable": "Não há backups disponíveis",
"NoHistory": "Sem histórico.",
"NoLeaveIt": "Não, deixe",
"NoLeaveIt": "Não, deixe-o",
"NoLimitForAnyRuntime": "Sem limite para qualquer tempo de execução",
"NoLogFiles": "Nenhum arquivo de registro",
"NoLogFiles": "Nenhum arquivo de log",
"NoMinimumForAnyRuntime": "Sem mínimo para qualquer tempo de execução",
"NoUpdatesAreAvailable": "Não há atualizações disponíveis",
"NoUpdatesAreAvailable": "Nenhuma atualização está disponível",
"None": "Vazio",
"NotificationTriggers": "Gatilhos de Notificação",
"OnGrabHelpText": "Ao obter",
@@ -260,20 +260,20 @@
"ProxyBypassFilterHelpText": "Use ',' como separador e '*.' como curinga para subdomínios",
"ProxyType": "Tipo de Proxy",
"ProxyUsernameHelpText": "Você só precisa digitar um nome de usuário e senha se for necessário. Caso contrário, deixe-os em branco.",
"PublishedDate": "Data de Publicação",
"PublishedDate": "Data de publicação",
"Quality": "Qualidade",
"QualityDefinitions": "Definições de Qualidade",
"QualityProfile": "Perfil de qualidade",
"QualityProfile": "Perfil de Qualidade",
"QualityProfiles": "Perfis de Qualidade",
"QualitySettings": "Configurações de Qualidade",
"Queue": "Fila",
"RSSSync": "Sincronização RSS",
"RSSSyncInterval": "Intervalo da sincronização RSS",
"ReadTheWikiForMoreInformation": "Leia o Wiki para obter mais informações",
"ReadTheWikiForMoreInformation": "Leia o Wiki para mais informações",
"ReadarrSupportsAnyIndexerThatUsesTheNewznabStandardAsWellAsOtherIndexersListedBelow": "O Readarr oferece suporte a qualquer indexador que usa o padrão Newznab, além de outros indexadores, listados abaixo.",
"ReadarrTags": "Tags do Readarr",
"Real": "Real",
"Reason": "Razão",
"Reason": "Motivo",
"RecycleBinCleanupDaysHelpText": "Defina como 0 para desabilitar a limpeza automática",
"RecycleBinCleanupDaysHelpTextWarning": "Os arquivos na lixeira mais antigos do que o número de dias selecionado serão limpos automaticamente",
"RecycleBinHelpText": "Arquivos de livros vêm para cá quando excluídos, em vez de serem apagados permanentemente",
@@ -283,7 +283,7 @@
"Refresh": "Atualizar",
"RefreshInformationAndScanDisk": "Atualizar as informações e verificar o disco",
"ReleaseDate": "Data de lançamento",
"ReleaseGroup": "Grupo de lançamento",
"ReleaseGroup": "Grupo do Lançamento",
"ReleaseRejected": "Versão rejeitada",
"ReleaseWillBeProcessedInterp": "A versão será processada {0}",
"Reload": "Recarregar",
@@ -292,13 +292,13 @@
"RemoveCompletedDownloadsHelpText": "Remover downloads importados do histórico do cliente de download",
"RemoveFailedDownloadsHelpText": "Remova downloads com falha do histórico do cliente de download",
"RemoveFilter": "Remover filtro",
"RemoveFromDownloadClient": "Remover do cliente de download",
"RemoveFromDownloadClient": "Remover Do Cliente de Download",
"RemoveFromQueue": "Remover da fila",
"RemoveHelpTextWarning": "Isso removerá o download e o(s) arquivo(s) do cliente de download.",
"RemoveSelected": "Remover Selecionado",
"RemoveSelected": "Remover selecionado(s)",
"RemoveTagExistingTag": "Tag existente",
"RemoveTagRemovingTag": "Removendo tag",
"RemovedFromTaskQueue": "Removido da Fila de Tarefas",
"RemovedFromTaskQueue": "Removido da fila de tarefas",
"RenameBooksHelpText": "O Readarr usará o nome de arquivo existente se a renomeação estiver desativada",
"Reorder": "Reordenar",
"ReplaceIllegalCharacters": "Substituir Caracteres Ilegais",
@@ -318,17 +318,17 @@
"Retention": "Retenção",
"RetentionHelpText": "Somente Usenet: defina como zero para definir a retenção ilimitada",
"RetryingDownloadInterp": "Tentando novamente o download {0} em {1}",
"RootFolder": "Pasta raiz",
"RootFolder": "Pasta Raiz",
"RootFolders": "Pastas Raiz",
"RssSyncIntervalHelpText": "Intervalo em minutos. Defina como zero para desativar (isso interromperá todas as capturas de lançamentos automáticas)",
"SSLCertPassword": "Senha do certificado SSL",
"SSLCertPath": "Caminho do certificado SSL",
"SSLPort": "Porta SSL",
"Scheduled": "Programado",
"Scheduled": "Agendado",
"ScriptPath": "Caminho do Script",
"Search": "Pesquisar",
"SearchAll": "Pesquisar tudo",
"SearchForMissing": "Pesquisar por Ausentes",
"SearchForMissing": "Pesquisar ausentes",
"SearchSelected": "Pesquisar selecionado(s)",
"Security": "Segurança",
"SendAnonymousUsageData": "Enviar dados de uso anônimos",
@@ -355,15 +355,15 @@
"SkipFreeSpaceCheckWhenImportingHelpText": "Use quando o Readarr não conseguir detectar espaço livre na pasta raiz do autor",
"SorryThatAuthorCannotBeFound": "Desculpe, esse autor não pode ser encontrado.",
"SorryThatBookCannotBeFound": "Desculpe, esse livro não pode ser encontrado.",
"Source": "Origem",
"SourcePath": "Caminho da Fonte",
"Source": "Fonte",
"SourcePath": "Caminho da fonte",
"SslCertPasswordHelpText": "Senha para arquivo pfx",
"SslCertPathHelpText": "Caminho para o arquivo pfx",
"SslPortHelpTextWarning": "Requer reinício para ter efeito",
"StandardBookFormat": "Formato de livro padrão",
"StartTypingOrSelectAPathBelow": "Comece a digitar ou selecione um caminho abaixo",
"StartupDirectory": "Diretório de inicialização",
"Status": "Status",
"Status": "Estado",
"StatusEndedEnded": "Terminado",
"Style": "Estilo",
"SuccessMyWorkIsDoneNoFilesToRename": "Êba, já terminei! Não há arquivos a renomear.",
@@ -373,9 +373,9 @@
"SupportsSearchvalueWillBeUsedWhenAutomaticSearchesArePerformedViaTheUIOrByReadarr": "Será usado quando pesquisas automáticas forem realizadas pela interface ou pelo Readarr",
"SupportsSearchvalueWillBeUsedWhenInteractiveSearchIsUsed": "Será usado com a pesquisa interativa",
"TagIsNotUsedAndCanBeDeleted": "A tag não é usada e pode ser excluída",
"Tags": "Etiquetas",
"Tags": "Tags",
"Tasks": "Tarefas",
"TestAll": "Testar tudo",
"TestAll": "Testar Tudo",
"TestAllClients": "Testar todos os clientes",
"TestAllIndexers": "Testar todos os indexadores",
"TestAllLists": "Testar todas as listas",
@@ -391,7 +391,7 @@
"UILanguageHelpTextWarning": "É necessário recarregar o navegador",
"UISettings": "Configurações da interface",
"UnableToAddANewRootFolderPleaseTryAgain": "Não foi possível adicionar uma nova pasta raiz, tente novamente.",
"UnableToLoadBackups": "Não é possível carregar backups",
"UnableToLoadBackups": "Não foi possível carregar os backups",
"UnableToLoadDelayProfiles": "Não foi possível carregar os perfis de atraso",
"UnableToLoadDownloadClientOptions": "Não foi possível carregar as opções do cliente de download",
"UnableToLoadDownloadClients": "Não foi possível carregar os clientes de download",
@@ -448,7 +448,7 @@
"UpdatingIsDisabledInsideADockerContainerUpdateTheContainerImageInstead": "A atualização está desabilitada no contêiner do Docker. Atualize a imagem do contêiner.",
"UpdateCoversHelpText": "Fazer com que as capas de livros do Calibre correspondam às do Readarr",
"UpdateCovers": "Atualizar capas",
"UnmappedFiles": "Arquivos Não Mapeados",
"UnmappedFiles": "Arquivos não mapeados",
"UnableToLoadMetadataProviderSettings": "Não foi possível carregar as configurações do provedor de metadados",
"TrackTitle": "Título da faixa",
"TrackNumber": "Número da faixa",
@@ -528,7 +528,7 @@
"MinimumPages": "Mínimo de páginas",
"MinPopularityHelpText": "Popularidade = Classificação média × Número de votos",
"MetadataSourceHelpText": "Fonte alternativa de metadados (deixe em branco para usar o padrão)",
"MetadataSource": "Fonte de metadados",
"MetadataSource": "Fonte de Metadados",
"MetadataProviderSource": "Fonte do provedor de metadados",
"MetadataProfiles": "Perfis de metadados",
"MetadataProfileIdHelpText": "Adicionar itens da lista do Perfil de metadados com",
@@ -581,7 +581,7 @@
"EmbedMetadataInBookFiles": "Incorporar metadados nos arquivos do livro",
"EmbedMetadataHelpText": "Pedir ao Calibre para gravar metadados no arquivo do livro",
"EditionsHelpText": "Alterar edição para este livro",
"MaintenanceRelease": "Versão de manutenção: correções de bugs e outros aprimoramentos. Consulte o Histórico de Commit do Github para obter mais detalhes",
"MaintenanceRelease": "Versão de manutenção: correções de bugs e outras melhorias. Veja Github Commit History para mais detalhes",
"EditAuthor": "Editar autor",
"DownloadPropersAndRepacksHelpTexts2": "Use \"Não preferir\" para classificar por pontuação de palavra preferida em relação a Propers/Repacks",
"DownloadClientCheckDownloadingToRoot": "O cliente de download {0} coloca os downloads na pasta raiz {1}. Você não deve baixar para uma pasta raiz.",
@@ -663,7 +663,7 @@
"BookTitle": "Título do livro",
"OutputPath": "Caminho de saída",
"Progress": "Progresso",
"ReleaseTitle": "Título da versão",
"ReleaseTitle": "Título do Lançamento",
"Actions": "Ações",
"FilterAuthor": "Filtro de Autor",
"NameFirstLast": "Primeiro Nome Último Nome",
@@ -687,12 +687,12 @@
"SeriesTotal": "Séries ({0})",
"TooManyBooks": "Livros ausentes ou muitos? Modifique ou crie um novo",
"BlocklistRelease": "Lançamento na lista de bloqueio",
"NoHistoryBlocklist": "Sem histórico na lista de bloqueio",
"NoHistoryBlocklist": "Nenhum histórico na lista de bloqueio",
"Blocklist": "Lista de Bloqueio",
"RemoveFromBlocklist": "Remover da lista de bloqueio",
"UnableToLoadBlocklist": "Incapaz de carregar a lista de bloqueio",
"ReleaseBranchCheckOfficialBranchMessage": "Ramo {0} não é um ramo válido de lançamentos do Readarr, você não irá receber atualizações",
"Time": "Tempo",
"Time": "Horário",
"IgnoredMetaHelpText": "Livros irão ser ignorados se eles conterem um ou mais termos (não diferenciando maiúscula de minuscula)",
"Component": "Componente",
"Level": "Nível",
@@ -783,7 +783,7 @@
"IndexerStatusCheckAllClientMessage": "Todos os indexadores estão indisponíveis devido a falhas",
"IndexerStatusCheckSingleClientMessage": "Indexadores indisponíveis devido a falhas: {0}",
"Lists": "Listas",
"MediaManagement": "Gerenciamento de mídia",
"MediaManagement": "Gerenciamento de Mídia",
"MediaManagementSettingsSummary": "Nomenclatura, configurações de gerenciamento de arquivos e pastas raiz",
"Metadata": "Metadados",
"MissingFromDisk": "Readarr não conseguiu encontrar o arquivo no disco, então o arquivo foi desvinculado do livro no banco de dados",
@@ -794,8 +794,8 @@
"ProxyCheckBadRequestMessage": "Falha ao testar o proxy. Código de status: {0}",
"ProxyCheckFailedToTestMessage": "Falha ao testar o proxy: {0}",
"QualitySettingsSummary": "Tamanhos de qualidade e nomenclatura",
"Queued": "Na fila",
"QueueIsEmpty": "A fila está vazia",
"Queued": "Enfileirados",
"QueueIsEmpty": "Fila está vazia",
"RefreshAndScan": "Atualizar & Escanear",
"RefreshBook": "Atualizar Livro",
"ReadarrSupportsAnyDownloadClient": "Readarr suporta muitos clientes populares de download de torrent e usenet.",
@@ -878,7 +878,7 @@
"ApiKeyValidationHealthCheckMessage": "Atualize sua chave de API para ter pelo menos {0} caracteres. Você pode fazer isso através das configurações ou do arquivo de configuração",
"DeleteFormat": "Excluir Formato",
"DataFutureBooks": "Monitorar livros que ainda não foram lançados",
"DeleteFormatMessageText": "Tem certeza de que deseja excluir a tag de formato '{0}'?",
"DeleteFormatMessageText": "Tem certeza de que deseja excluir a etiqueta de formato {0} ?",
"IncludeCustomFormatWhenRenamingHelpText": "'Incluir em {Formatos Personalizados} formato de renomeação'",
"IndexerTagsHelpText": "Use este indexador apenas para autores com pelo menos uma etiqueta correspondente. Deixe em branco para usar com todos os autores.",
"MinFormatScoreHelpText": "Pontuação mínima de formato personalizado permitida para download",
@@ -892,22 +892,22 @@
"CustomFormats": "Formatos personalizados",
"CutoffFormatScoreHelpText": "Depois que essa pontuação de formato personalizado for alcançada, Readarr não obterá mais lançamentos de livros",
"DeleteCustomFormat": "Excluir formato personalizado",
"ExportCustomFormat": "Exportar formato personalizado",
"ExportCustomFormat": "Exportar Formato Personalizado",
"Formats": "Formatos",
"Loading": "carregando",
"NegateHelpText": "Se marcado, o formato personalizado não será aplicado se esta condição {0} corresponder.",
"ThereWasAnErrorLoadingThisItem": "Ocorreu um erro ao carregar este item",
"ThereWasAnErrorLoadingThisPage": "Ocorreu um erro ao carregar esta página",
"UpgradesAllowed": "Atualizações Permitidas",
"DeleteCustomFormatMessageText": "Tem certeza de que deseja excluir o formato personalizado '{name}'?",
"DeleteCustomFormatMessageText": "Tem certeza de que deseja excluir o formato personalizado '{0}'?",
"ImportListMissingRoot": "Pasta raiz ausente para lista(s) de importação: {0}",
"ImportListMultipleMissingRoots": "Várias pastas raiz estão ausentes para listas de importação: {0}",
"IndexerDownloadClientHelpText": "Especifique qual cliente de download é usado para baixar deste indexador",
"ListRefreshInterval": "Intervalo de atualização da lista",
"ListWillRefreshEveryInterp": "A lista será atualizada a cada {0}",
"ResetDefinitionTitlesHelpText": "Redefinir títulos de definição e valores",
"ResetDefinitionTitlesHelpText": "Redefinir títulos de definição, bem como valores",
"ResetDefinitions": "Redefinir Definições",
"ResetTitles": "Redefinir títulos",
"ResetTitles": "Redefinir Títulos",
"UnableToLoadCustomFormats": "Não foi possível carregar formatos personalizados",
"HiddenClickToShow": "Oculto, clique para mostrar",
"HideAdvanced": "Ocultar Avançado",
@@ -922,24 +922,24 @@
"DeleteRemotePathMapping": "Excluir Mapeamento de Caminho Remoto",
"BlocklistReleases": "Lançamentos na lista de bloqueio",
"CloneCondition": "Condição de clone",
"DeleteConditionMessageText": "Tem certeza de que deseja excluir a condição '{name}'?",
"DeleteConditionMessageText": "Tem certeza de que deseja excluir a condição '{0}'?",
"DeleteRemotePathMappingMessageText": "Tem certeza de que deseja excluir este mapeamento de caminho remoto?",
"DeleteCondition": "Excluir condição",
"Negated": "Negado",
"RemoveSelectedItem": "Remover item selecionado",
"RemoveSelectedItem": "Remover Item Selecionado",
"RemoveSelectedItemBlocklistMessageText": "Tem certeza de que deseja remover os itens selecionados da lista de bloqueio?",
"RemoveSelectedItems": "Remover itens selecionados",
"RemoveSelectedItems": "Remover Itens Selecionados",
"RemoveSelectedItemQueueMessageText": "Tem certeza de que deseja remover 1 item da fila?",
"RemoveSelectedItemsQueueMessageText": "Tem certeza de que deseja remover {0} itens da fila?",
"Required": "Necessário",
"ResetQualityDefinitions": "Redefinir definições de qualidade",
"Required": "Requerido",
"ResetQualityDefinitions": "Redefinir Definições de Qualidade",
"ResetQualityDefinitionsMessageText": "Tem certeza de que deseja redefinir as definições de qualidade?",
"BlocklistReleaseHelpText": "Evita que o Readarr pegue automaticamente esses arquivos novamente",
"NoCutoffUnmetItems": "Nenhum item de corte não atendido",
"NoEventsFound": "Não foram encontrados eventos",
"NoEventsFound": "Nenhum evento encontrado",
"NoMissingItems": "Nenhum item faltando",
"CountImportListsSelected": "{selectedCount} lista(s) de importação selecionada(s)",
"CountIndexersSelected": "{selectedCount} indexador(es) selecionado(s)",
"CountImportListsSelected": "{0} lista(s) de importação selecionada(s)",
"CountIndexersSelected": "{0} indexador(es) selecionado(s)",
"EditSelectedDownloadClients": "Editar clientes de download selecionados",
"EditSelectedImportLists": "Editar listas de importação selecionadas",
"EditSelectedIndexers": "Editar indexadores selecionados",
@@ -970,12 +970,12 @@
"ApplyTagsHelpTextHowToApplyDownloadClients": "Como aplicar tags aos clientes de download selecionados",
"ApplyTagsHelpTextHowToApplyImportLists": "Como aplicar tags às listas de importação selecionadas",
"ApplyTagsHelpTextHowToApplyIndexers": "Como aplicar tags aos indexadores selecionados",
"CountDownloadClientsSelected": "{selectedCount} cliente(s) de download selecionado(s)",
"DeleteSelectedIndexersMessageText": "Tem certeza de que deseja excluir {count} indexadores selecionados?",
"CountDownloadClientsSelected": "{0} cliente(s) de download selecionado(s)",
"DeleteSelectedIndexersMessageText": "Tem certeza de que deseja excluir {0} indexador(es) selecionado(s)?",
"DeleteSelectedDownloadClients": "Excluir cliente(s) de download",
"DeleteSelectedDownloadClientsMessageText": "Tem certeza de que deseja excluir {count} cliente(s) de download selecionado(s)?",
"DeleteSelectedDownloadClientsMessageText": "Tem certeza de que deseja excluir {0} cliente(s) de download selecionado(s)?",
"DeleteSelectedImportLists": "Excluir lista(s) de importação",
"DeleteSelectedImportListsMessageText": "Tem certeza de que deseja excluir {count} lista(s) de importação selecionada(s)?",
"DeleteSelectedImportListsMessageText": "Tem certeza de que deseja excluir {0} lista(s) de importação selecionada(s)?",
"DeleteSelectedIndexers": "Excluir indexador(es)",
"DownloadClientTagHelpText": "Use este cliente de download apenas para autores com pelo menos uma etiqueta correspondente. Deixe em branco para usar com todos os autores.",
"ExistingTag": "Etiqueta existente",
@@ -983,38 +983,5 @@
"RemoveCompletedDownloads": "Remover downloads concluídos",
"RemovingTag": "Removendo etiqueta",
"SkipRedownloadHelpText": "Impede Readarr de tentar baixar versões alternativas para os itens removidos",
"IndexerDownloadClientHealthCheckMessage": "Indexadores com clientes de download inválidos: {0}.",
"Activity": "Atividade",
"Bookshelf": "Prateleira",
"Events": "Eventos",
"FreeSpace": "Espaço Livre",
"NextExecution": "Próxima Execução",
"Small": "Pequeno",
"TotalSpace": "Espaço Total",
"Location": "Localização",
"Medium": "Médio",
"AddNew": "Adicionar Novo",
"Backup": "Backup",
"Large": "Grande",
"LastDuration": "Última Duração",
"LastExecution": "Última Execução",
"LastWriteTime": "Hora da Última Gravação",
"Library": "Biblioteca",
"System": "Sistema",
"Ui": "IU",
"NotificationStatusAllClientHealthCheckMessage": "Todas as notificações estão indisponíveis devido a falhas",
"NotificationStatusSingleClientHealthCheckMessage": "Notificações indisponíveis devido a falhas: {0}",
"AllResultsAreHiddenByTheAppliedFilter": "Todos os resultados são ocultados pelo filtro aplicado",
"SomeResultsAreHiddenByTheAppliedFilter": "Alguns resultados estão ocultos pelo filtro aplicado",
"NoResultsFound": "Nenhum resultado encontrado",
"ConnectionLostReconnect": "{appName} tentará se conectar automaticamente ou você pode clicar em recarregar abaixo.",
"AutomaticUpdatesDisabledDocker": "As atualizações automáticas não têm suporte direto ao usar o mecanismo de atualização do Docker. Você precisará atualizar a imagem do contêiner fora de {appName} ou usar um script",
"WouldYouLikeToRestoreBackup": "Gostaria de restaurar o backup '{name}'?",
"AppUpdated": "{appName} Atualizado",
"AppUpdatedVersion": "{appName} foi atualizado para a versão `{version}`, para obter as alterações mais recentes, você precisará recarregar {appName}",
"ConnectionLost": "Conexão Perdida",
"ConnectionLostToBackend": "{appName} perdeu sua conexão com o backend e precisará ser recarregado para restaurar a funcionalidade.",
"CountAuthorsSelected": "{selectedCount} autor(es) selecionado(s)",
"RecentChanges": "Mudanças Recentes",
"WhatsNew": "O quê há de novo?"
"IndexerDownloadClientHealthCheckMessage": "Indexadores com clientes de download inválidos: {0}."
}

View File

@@ -587,7 +587,7 @@
"RemoveSelectedItemsQueueMessageText": "Sigur doriți să eliminați {0} elementul {1} din coadă?",
"ApplyTagsHelpTextHowToApplyAuthors": "Cum se aplică etichete indexatoarelor selectate",
"CountIndexersSelected": "{0} Indexatoare selectate",
"DeleteSelectedDownloadClients": "Ștergere clienți de descărcare",
"DeleteSelectedDownloadClients": "Ștergeți clientul de descărcare",
"ExistingTag": "Etichetă existentă",
"No": "Nu",
"NoChange": "Nicio Modificare",
@@ -613,34 +613,5 @@
"CloneCondition": "Clonați condiție",
"InstanceName": "Nume instanță",
"Publisher": "Editor",
"Implementation": "Implementarea",
"Authentication": "Autentificare",
"ResetQualityDefinitions": "Resetare definitii de calitate",
"ChooseImportMethod": "Alege modul de import",
"NotificationStatusSingleClientHealthCheckMessage": "Aplicații indisponibile datorită erorilor: {0}",
"Small": "Mic",
"Ui": "Interfață Grafica",
"Events": "Evenimente",
"Large": "Mare",
"Library": "Bibliotecă",
"SomeResultsAreHiddenByTheAppliedFilter": "Unele rezultate sunt ascunse de filtrul aplicat",
"ConnectionLostReconnect": "{appName} va încerca să se conecteze automat, sau poți apăsa reîncarcă mai jos.",
"ConnectionLostToBackend": "{appName} a pierdut conexiunea cu backend-ul și trebuie reîncărcat pentru a restabili funcționalitatea.",
"FreeSpace": "Spațiu Liber",
"LastDuration": "Ultima durată",
"LastExecution": "Ultima executare",
"LastWriteTime": "Data ultimei scrieri",
"Location": "Locație",
"NextExecution": "Următoarea execuție",
"RecentChanges": "Schimbări recente",
"ResetDefinitions": "Resetare definitii",
"System": "Sistem",
"TotalSpace": "Spațiu Total",
"WhatsNew": "Ce mai e nou?",
"NoResultsFound": "Nici un rezultat gasit",
"Activity": "Activitate",
"AddNew": "Adaugă nou",
"Medium": "Mediu",
"AllResultsAreHiddenByTheAppliedFilter": "Toate rezultatele sunt ascunse de filtrul aplicat",
"Backup": "Copie de rezervă"
"Implementation": "Implementarea"
}

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