Compare commits

...

75 Commits

Author SHA1 Message Date
Qstick
fa304dcaca Random 2022-01-02 23:39:55 -06:00
Qstick
e04133d34a More Mono Cleaning 2022-01-02 23:19:47 -06:00
Qstick
07575ae239 Fixed: (LazyLibrarian) Test indexer pull on setup to validate 2022-01-02 21:50:44 -06:00
Qstick
8e7acd8946 Fixed: (Mylar) Test indexer pull on setup to validate Mylar functionality 2022-01-02 21:50:44 -06:00
Qstick
3ecc926298 Fixed: (HDTorrents) Use Sanitized search string on all search types 2022-01-02 19:43:46 -06:00
Qstick
1e532624af Fixed: (Redacted) Guid and FL Parsing in line with Gazelle 2022-01-02 16:45:34 -06:00
Agneev Mukherjee
8a5194e604 Update index.ejs 2022-01-02 13:10:07 -06:00
Agneev Mukherjee
8a73cf72c2 Set login.html theme-color to color of logo 2022-01-02 13:10:07 -06:00
Qstick
76982c5988 Fixed: (Gazelle) Freeleech detection for releases 2022-01-01 20:08:59 -06:00
Qstick
b9dfe5e359 Fixed: (Gazelle) Use InfoUrl for GUID to avoid global duplicates 2022-01-01 20:01:40 -06:00
Qstick
a5e13ca776 New: Genre parameter for Music search 2022-01-01 15:04:05 -06:00
Qstick
e2ddfbff9c New: Genre parameter for Movie search 2022-01-01 14:49:01 -06:00
Qstick
66b4c7891d New: TmdbId Parameter for TV Search 2022-01-01 14:43:49 -06:00
Qstick
480a76c290 New: Support for language metadata 2022-01-01 14:23:44 -06:00
Servarr
1373ab255d Automated API Docs update 2021-12-31 19:41:04 -06:00
Qstick
1dc00eb445 More powerful label actions 2021-12-31 19:34:28 -06:00
Qstick
a366bec684 New: Reenable TV Id search for PrivateHD 2021-12-31 19:34:28 -06:00
Qstick
ecca6e9f49 New: TVDB and TMDB Search for AvistaZ
Ref #717
2021-12-31 19:34:13 -06:00
Yukine
03db7a9bbd Fixed: (SpeedApp) correct categories in query string of requests 2021-12-31 15:09:03 -06:00
Qstick
9cb04466c1 DbType param on update check 2021-12-31 13:19:22 -06:00
bakerboy448
2bae37d0c5 Fixed: (TorrentLeech) Calculating Incorrect Age
Closes #720
2021-12-31 11:04:31 -06:00
bakerboy448
0dbd23c52b Fixed: Various Translations 2021-12-30 23:34:48 -06:00
bakerboy448
66a6311dcc Fixed: SemiPublic => SemiPrivate 2021-12-30 23:00:19 -06:00
Servarr
c5b111530c Automated API Docs update 2021-12-30 22:37:20 -06:00
Qstick
77724a50a4 Really fix Github token for API PR 2021-12-30 21:42:46 -06:00
Qstick
22cbd01c57 Bump to 0.1.10 2021-12-30 19:03:04 -06:00
Yukine
fd55a624a7 Fixed: (AnimeBytes) Do not Page requests 2021-12-30 19:01:42 -06:00
Qstick
75984e954e Update LocalizationController.cs 2021-12-30 18:41:56 -06:00
Qstick
3fce120578 Fixed: (SpeedApp) Map Categories instead of building
Fixes #574
2021-12-30 18:30:58 -06:00
Qstick
6e8fb22c71 New: Additional logging for InvalidModel BadRequest API calls
[common]
2021-12-30 17:51:34 -06:00
Qstick
8ec7a4898d Maintain PrimaryKey and AutoIncrement on some schemas
[common]
2021-12-30 17:51:11 -06:00
Qstick
642848d331 API Annotations 2021-12-30 15:51:51 -06:00
Qstick
c9e6a0339e Fixed: (Cardigann) Indexer privacy tweaks, Semi-Public fixes
Fixes #744
2021-12-29 18:18:09 -06:00
Qstick
25620e8670 Fix GitHub token variable usage 2021-12-29 18:16:36 -06:00
Mouton99
5b804e8f3a New: (TorrentSeeds) Migrate to API & YML 2021-12-29 18:14:22 -06:00
Servarr
548db6a5cd Automated API Docs update 2021-12-29 17:48:53 -06:00
Qstick
7f28f64cbe Fix server settings on API docs 2021-12-28 18:47:44 -06:00
Qstick
9bad31af84 Eliminate PR Extension from pipeline 2021-12-28 18:26:51 -06:00
Qstick
01c7a05841 Only push to api-docs when changes 2021-12-28 17:52:15 -06:00
Qstick
9859b4a3d9 force it 2021-12-28 17:37:30 -06:00
Gabriel Sjöberg
177084fe8b Fixed: (Indexer) Update RARBG API query options
* Added app_id to captcha check to avoid 403 forbidden error
* Migrated app_id from hard coded to BuildInfo.AppName
2021-12-28 17:04:55 -06:00
Qstick
c57a91bc64 Skip build of doc only change, ignore PR errors for docs 2021-12-28 17:01:31 -06:00
Servarr
ca67a40c72 Automated API Docs update 2021-12-28 15:39:14 -06:00
Qstick
de7505bbe6 correctly push upstream 2021-12-28 15:27:54 -06:00
Qstick
97956ce951 Branch and push prior to PR 2021-12-28 15:10:56 -06:00
Qstick
8a38e124fd Speed up Checkout for Docs job 2021-12-28 14:45:28 -06:00
Qstick
38fcffe871 Identify user for git 2021-12-28 14:31:12 -06:00
Qstick
4c7b5a47d3 Autogenerated API docs 2021-12-28 13:43:45 -06:00
Qstick
34597e6ecb Boolean default should be a boolean
Fixes #729
2021-12-24 14:23:09 -06:00
bakerboy448
735be4f467 New: (TvVault) Mark as Obsolete per Site Bot Ban
Closes #573
2021-12-24 14:08:00 -06:00
bakerboy448
1c737d77fb Bump to 0.1.9 2021-12-24 14:07:42 -06:00
bakerboy448
55788ac04d Fixed: (Usenet) (DrunkenSlug) Update URL
https://api.drunkenslug.com gives a 301
2021-12-24 14:07:17 -06:00
bakerboy448
d108ab0339 Fix misleading Tags helptext [skip ci] 2021-12-24 14:06:42 -06:00
bakerboy448
5928eea83e Fixed: (PornoLab) Add new 2022 Categories
Based on Jackett f61a2b47400e68422ba6620a5ef2f5b4d0a929a3
2021-12-24 12:58:51 -06:00
bakerboy448
27898aa3b5 Fixed: (DanishBytes) Update Domain to .club
Based on Jackett f890ddd119a35eb4ba40b407aa65461c713b5e5d
2021-12-24 12:58:51 -06:00
bakerboy448
5e3322c538 New: OnApplicationUpdate Notifications
(based on Radarr Commits
9e175e28efcfc6ac3e414649b955a10fb0e951e7
4f5f9ff77ee4de05ba04cc677eb7baf4df726af5
4ebcbc28aa3e3268ecc37c5fc2b5565da8f13305
)
Fixes #723

Co-authored-by: Qstick <qstick@gmail.com>
2021-12-22 19:07:07 -06:00
bakerboy448
80c31e8660 fixup add rationale for Obsolete of C# Indexer Implementations 2021-12-18 09:34:51 -06:00
bakerboy448
46401ee187 Fixed: (BB) Remove '.' from Search String
based on jackett fbb1f15d7014b2d8c23c6ee94c2bcf37612066db
2021-12-18 09:27:26 -06:00
Davo1624
3610becc64 Fixed: (Orpheus) Drop Caps Support for Movie & TV Search
Drop TV and Movie search as no Movie/TV categories (#713)

e-learning results are how to play guitar videos, etc
comedy are comedy/standup recordings
2021-12-15 16:30:26 -06:00
Davo1624
06d9c157d8 Fixed: (Orpheus) Map Categories Comedy & E-Learning Videos to 'Other'
indexer does not actually have movies and tv
2021-12-15 16:27:50 -06:00
bakerboy448
d0d1f40128 Fixed: (Anilibria) Duplicate entries
Mark C# Anilibria as obsolete
2021-12-12 17:28:07 -06:00
bakerboy448
383d5464b7 New: (FlareSolverr Proxy) Configurable Request Timeout
Closes #696
2021-12-11 22:10:06 -06:00
Qstick
62d15536df Fixed: NullRef in SchemaBuilder when sending payload without optional Provider.Settings fields 2021-12-11 13:38:25 -06:00
ta264
147cdf2cce Fixed: Forms login persists across restarts in docker
(cherry picked from commit a219b4a1b869863b2ef47d4bdf33d308cb261ba3)

Fixes #409
2021-12-10 03:14:55 -06:00
bakerboy448
dd27d69e97 fix erroneous logging for windows service on non-windows 2021-12-10 03:14:23 -06:00
Robin Dadswell
32fd0911a2 New: Application Placeholders instead of default values 2021-12-09 15:19:11 -06:00
Robin Dadswell
0e6ec58a83 New: Placeholders in notification fields 2021-12-09 15:19:11 -06:00
Robin Dadswell
69f5963f6f New: Frontend Placeholders from the Backend 2021-12-09 15:19:11 -06:00
PearsonFlyer
6ca708f523 Fixed: (HDTorrents) Remove . from searches 2021-12-08 14:26:46 -06:00
ta264
9e7af8369e Fixed: Support older glibc in libMonoPosixHelper 2021-12-08 19:14:25 +00:00
Qstick
b05d8c930d Date Routines Test Cases 2021-12-07 20:19:05 -06:00
Qstick
6b886b938c New: Better Fuzzy DateTime Parse 2021-12-07 18:48:46 -06:00
ta264
4a7bf39723 Fixed: Speed up parsing DateTime 2021-12-06 21:57:22 +00:00
bakerboy448
7fcd320e23 Fixed: (PrivateHD) Drop support for IMDB search
imdb search does not support S/E params
this matches the behavior for TorrentLeech
Fixes #119
2021-12-06 21:12:37 -06:00
Qstick
88677ce236 Bump to 0.1.8 2021-12-06 17:19:04 -06:00
146 changed files with 1769 additions and 1103 deletions

16
.github/label-actions.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
# Configuration for Label Actions - https://github.com/dessant/label-actions
'Type: Support':
comment: >
:wave: @{issue-author}, we use the issue tracker exclusively
for bug reports and feature requests. However, this issue appears
to be a support request. Please hop over onto our [Discord](https://prowlarr.com/discord)
or [Subreddit](https://reddit.com/r/prowlarr)
close: true
'Type: Indexer Request':
comment: >
:wave: @{issue-author}, we use the issue tracker exclusively
for bug reports and feature requests. However, this issue appears
to be a indexer request. Please use our Indexer request [site](https://requests.prowlarr.com/)
close: true

23
.github/workflows/label-actions.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
name: 'Label Actions'
on:
issues:
types: [labeled, unlabeled]
pull_request:
types: [labeled, unlabeled]
discussion:
types: [labeled, unlabeled]
permissions:
contents: read
issues: write
pull-requests: write
discussions: write
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/label-actions@v2
with:
process-only: 'issues, prs'

View File

@@ -1,21 +0,0 @@
name: 'Support requests'
on:
issues:
types: [labeled, unlabeled, reopened]
jobs:
support:
runs-on: ubuntu-latest
steps:
- uses: dessant/support-requests@v2
with:
github-token: ${{ github.token }}
support-label: 'Type: Support'
issue-comment: >
:wave: @{issue-author}, we use the issue tracker exclusively
for bug reports and feature requests. However, this issue appears
to be a support request. Please hop over onto our [Discord](https://prowlarr.com/discord)
or [Subreddit](https://reddit.com/r/prowlarr)
close-issue: true
lock-issue: false

4
.gitignore vendored
View File

@@ -188,6 +188,10 @@ packages.config.md5sum
**/.idea/**/*.iml
**/.idea/**/contentModel.xml
**/.idea/**/modules.xml
# ignore node_modules symlink
node_modules
node_modules.nosync
# API doc generation
.config/

View File

@@ -7,7 +7,7 @@ variables:
outputFolder: './_output'
artifactsFolder: './_artifacts'
testsFolder: './_tests'
majorVersion: '0.1.7'
majorVersion: '0.1.10'
minorVersion: $[counter('minorVersion', 1)]
prowlarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(prowlarrVersion)'
@@ -29,6 +29,7 @@ pr:
paths:
exclude:
- src/NzbDrone.Core/Localization/Core
- src/Prowlarr.API.*/openapi.json
stages:
- stage: Setup
@@ -823,6 +824,59 @@ stages:
FORCE_COLOR: 0
YARN_CACHE_FOLDER: $(yarnCacheFolder)
- 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'))
)
pool:
vmImage: windows-2019
steps:
- task: UseDotNet@2
displayName: 'Install .net core'
inputs:
version: $(dotnetVersion)
- checkout: self
submodules: true
persistCredentials: true
fetchDepth: 1
- bash: ./docs.sh Windows
displayName: Create openapi.json
- bash: |
git config --global user.email "development@lidarr.audio"
git config --global user.name "Servarr"
git checkout -b api-docs
git add .
if git status | grep -q modified
then
git commit -am 'Automated API Docs update'
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/prowlarr/prowlarr/pulls -d '{"head":"api-docs","base":"develop","title":"Update API docs"}'
else
echo "No changes since last run"
fi
displayName: Commit API Doc Change
continueOnError: true
env:
GITHUBTOKEN: $(githubToken)
- task: CopyFiles@2
displayName: 'Copy openapi.json to: $(Build.ArtifactStagingDirectory)'
inputs:
SourceFolder: '$(Build.SourcesDirectory)'
Contents: |
**/*openapi.json
TargetFolder: '$(Build.ArtifactStagingDirectory)/api_docs'
- publish: $(Build.ArtifactStagingDirectory)/api_docs
artifact: 'APIDocs'
displayName: Publish API Docs Bundle
condition: and(succeeded(), eq(variables['System.JobAttempt'], '1'))
- job: Analyze_Backend
displayName: Backend
dependsOn: Prepare

38
docs.sh Normal file
View File

@@ -0,0 +1,38 @@
PLATFORM=$1
if [ "$PLATFORM" = "Windows" ]; then
RUNTIME="win-x64"
elif [ "$PLATFORM" = "Linux" ]; then
WHERE="linux-x64"
elif [ "$PLATFORM" = "Mac" ]; then
WHERE="osx-x64"
else
echo "Platform must be provided as first arguement: Windows, Linux or Mac"
exit 1
fi
outputFolder='_output'
testPackageFolder='_tests'
rm -rf $outputFolder
rm -rf $testPackageFolder
slnFile=src/Prowlarr.sln
platform=Posix
dotnet clean $slnFile -c Debug
dotnet clean $slnFile -c Release
dotnet msbuild -restore $slnFile -p:Configuration=Debug -p:Platform=$platform -p:RuntimeIdentifiers=$RUNTIME -t:PublishAllRids
dotnet new tool-manifest
dotnet tool install --version 6.2.3 Swashbuckle.AspNetCore.Cli
dotnet tool run swagger tofile --output ./src/Prowlarr.Api.V1/openapi.json "$outputFolder/net6.0/$RUNTIME/prowlarr.console.dll" v1 &
sleep 10
kill %1
exit 0

View File

@@ -77,7 +77,9 @@ function AppUpdatedModalContent(props) {
<div>
{
!update.changes &&
<div className={styles.maintenance}>Maintenance release</div>
<div className={styles.maintenance}>
{translate('MaintenanceRelease')}
</div>
}
{

View File

@@ -166,7 +166,9 @@ class FilterBuilderModalContent extends Component {
</div>
</div>
<div className={styles.label}>Filters</div>
<div className={styles.label}>
{translate('Filters')}
</div>
<div className={styles.rows}>
{

View File

@@ -68,6 +68,7 @@ function ProviderFieldFormGroup(props) {
label,
helpText,
helpLink,
placeholder,
value,
type,
advanced,
@@ -100,6 +101,7 @@ function ProviderFieldFormGroup(props) {
label={label}
helpText={helpText}
helpLink={helpLink}
placeholder={placeholder}
value={value}
values={getSelectValues(selectOptions)}
errors={errors}
@@ -125,6 +127,7 @@ ProviderFieldFormGroup.propTypes = {
label: PropTypes.string,
helpText: PropTypes.string,
helpLink: PropTypes.string,
placeholder: PropTypes.string,
value: PropTypes.any,
type: PropTypes.string.isRequired,
advanced: PropTypes.bool.isRequired,

View File

@@ -41,7 +41,7 @@ function HistoryDetails(props) {
{
!!data &&
<DescriptionListItem
title={'Query Results'}
title={translate('QueryResults')}
data={queryResults ? queryResults : '-'}
/>
}
@@ -49,7 +49,7 @@ function HistoryDetails(props) {
{
!!data &&
<DescriptionListItem
title={'Categories'}
title={translate('Categories')}
data={categories ? categories : '-'}
/>
}
@@ -57,7 +57,7 @@ function HistoryDetails(props) {
{
!!data &&
<DescriptionListItem
title={'Source'}
title={translate('Source')}
data={source}
/>
}
@@ -65,7 +65,7 @@ function HistoryDetails(props) {
{
!!data &&
<DescriptionListItem
title={'Url'}
title={translate('Url')}
data={url ? <Link to={url}>{translate('Link')}</Link> : '-'}
/>
}
@@ -93,7 +93,7 @@ function HistoryDetails(props) {
{
!!data &&
<DescriptionListItem
title={'Source'}
title={translate('Source')}
data={source ? source : '-'}
/>
}
@@ -101,7 +101,7 @@ function HistoryDetails(props) {
{
!!data &&
<DescriptionListItem
title={'Title'}
title={translate('Title')}
data={title ? title : '-'}
/>
}
@@ -109,7 +109,7 @@ function HistoryDetails(props) {
{
!!data &&
<DescriptionListItem
title={'Url'}
title={translate('Url')}
data={url ? <Link to={url}>{translate('Link')}</Link> : '-'}
/>
}

View File

@@ -4,6 +4,7 @@ import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
class HistoryOptions extends Component {
@@ -56,14 +57,14 @@ class HistoryOptions extends Component {
return (
<Fragment>
<FormGroup>
<FormLabel>History Cleanup</FormLabel>
<FormLabel>{translate('HistoryCleanup')}</FormLabel>
<FormInputGroup
type={inputTypes.NUMBER}
name="historyCleanupDays"
value={historyCleanupDays}
helpText="Set to 0 to disable automatic cleanup"
helpTextWarning="History items older than the selected number of days will be cleaned up automatically"
helpText={translate('HistoryCleanupDaysHelpText')}
helpTextWarning={translate('HistoryCleanupDaysHelpTextWarning')}
onChange={this.onGlobalInputChange}
/>
</FormGroup>

View File

@@ -56,6 +56,21 @@ const protocols = [
}
];
const privacyLevels = [
{
key: 'private',
value: translate('Private')
},
{
key: 'semiPrivate',
value: translate('SemiPrivate')
},
{
key: 'public',
value: translate('Public')
}
];
class AddIndexerModalContent extends Component {
//
@@ -99,10 +114,6 @@ class AddIndexerModalContent extends Component {
.sort((a, b) => a.localeCompare(b))
.map((language) => ({ key: language, value: language }));
const privacyLevels = Array.from(new Set(indexers.map(({ privacy }) => privacy)))
.sort((a, b) => a.localeCompare(b))
.map((privacy) => ({ key: privacy, value: privacy }));
const filteredIndexers = indexers.filter((indexer) => {
const { filter, filterProtocols, filterLanguages, filterPrivacyLevels } = this.state;

View File

@@ -3,6 +3,8 @@ import React, { Component } from 'react';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRowButton from 'Components/Table/TableRowButton';
import ProtocolLabel from 'Indexer/Index/Table/ProtocolLabel';
import firstCharToUpper from 'Utilities/String/firstCharToUpper';
import translate from 'Utilities/String/translate';
import styles from './SelectIndexerRow.css';
class SelectIndexerRow extends Component {
@@ -47,7 +49,7 @@ class SelectIndexerRow extends Component {
</TableRowCell>
<TableRowCell>
{privacy}
{translate(firstCharToUpper(privacy))}
</TableRowCell>
</TableRowButton>
);

View File

@@ -159,7 +159,7 @@ function EditIndexerModalContent(props) {
<FormInputGroup
type={inputTypes.TAG}
name="tags"
helpText="Use tags to specify default clients, specify Indexer Proxies, or just to organize your indexers."
helpText={translate('IndexerTagsHelpText')}
{...tags}
onChange={onInputChange}
/>

View File

@@ -302,14 +302,14 @@ class IndexerIndex extends Component {
<PageToolbar>
<PageToolbarSection>
<PageToolbarButton
label={'Add Indexer'}
label={translate('AddIndexer')}
iconName={icons.ADD}
spinningName={icons.ADD}
onPress={this.onAddIndexerPress}
/>
<PageToolbarButton
label={'Test All Indexers'}
label={translate('TestAllIndexers')}
iconName={icons.TEST}
isSpinning={isTestingAll}
isDisabled={hasNoIndexer}
@@ -321,13 +321,13 @@ class IndexerIndex extends Component {
{
isMovieEditorActive ?
<PageToolbarButton
label={'Indexers'}
label={translate('Indexers')}
iconName={icons.MOVIE_CONTINUING}
isDisabled={hasNoIndexer}
onPress={this.onMovieEditorTogglePress}
/> :
<PageToolbarButton
label={'Mass Editor'}
label={translate('MassEditor')}
iconName={icons.EDIT}
isDisabled={hasNoIndexer}
onPress={this.onMovieEditorTogglePress}

View File

@@ -240,14 +240,14 @@ class IndexerIndexRow extends Component {
>
<IconButton
name={icons.INFO}
title={'Indexer info'}
title={translate('IndexerInfo')}
onPress={this.onIndexerInfoPress}
/>
<IconButton
className={styles.externalLink}
name={icons.EXTERNAL_LINK}
title={'Website'}
title={translate('Website')}
to={indexerUrls[0].replace('api.', '')}
/>

View File

@@ -299,7 +299,7 @@ class SearchIndexRow extends Component {
<IconButton
className={styles.downloadLink}
name={icons.SAVE}
title={'Save'}
title={translate('Save')}
to={downloadUrl}
/>
</VirtualTableRowCell>

View File

@@ -61,7 +61,7 @@ class Applications extends Component {
return (
<FieldSet legend={translate('Applications')}>
<PageSectionContent
errorMessage="Unable to load application list"
errorMessage={translate('UnableToLoadApplicationList')}
{...otherProps}
>
<div className={styles.applications}>

View File

@@ -61,7 +61,7 @@ class IndexerProxies extends Component {
} = this.state;
return (
<FieldSet legend={translate('Indexer Proxies')}>
<FieldSet legend={translate('IndexerProxies')}>
<PageSectionContent
errorMessage={translate('UnableToLoadIndexerProxies')}
{...otherProps}

View File

@@ -40,7 +40,7 @@ class Notification extends Component {
});
};
onDeleteNotificationModalClose= () => {
onDeleteNotificationModalClose = () => {
this.setState({ isDeleteNotificationModalOpen: false });
};
@@ -61,12 +61,14 @@ class Notification extends Component {
onRename,
onDelete,
onHealthIssue,
onApplicationUpdate,
supportsOnGrab,
supportsOnDownload,
supportsOnUpgrade,
supportsOnRename,
supportsOnDelete,
supportsOnHealthIssue
supportsOnHealthIssue,
supportsOnApplicationUpdate
} = this.props;
return (
@@ -82,53 +84,62 @@ class Notification extends Component {
{
supportsOnGrab && onGrab &&
<Label kind={kinds.SUCCESS}>
On Grab
{translate('OnGrab')}
</Label>
}
{
supportsOnDelete && onDelete &&
<Label kind={kinds.SUCCESS}>
On Delete
{translate('OnDelete')}
</Label>
}
{
supportsOnDownload && onDownload &&
<Label kind={kinds.SUCCESS}>
On Import
{translate('OnImport')}
</Label>
}
{
supportsOnUpgrade && onDownload && onUpgrade &&
<Label kind={kinds.SUCCESS}>
On Upgrade
{translate('OnUpgrade')}
</Label>
}
{
supportsOnRename && onRename &&
<Label kind={kinds.SUCCESS}>
On Rename
{translate('OnRename')}
</Label>
}
{
supportsOnHealthIssue && onHealthIssue &&
<Label kind={kinds.SUCCESS}>
On Health Issue
{translate('OnHealthIssue')}
</Label>
}
{
!onGrab && !onDownload && !onRename && !onHealthIssue && !onDelete &&
supportsOnApplicationUpdate && onApplicationUpdate ?
<Label kind={kinds.SUCCESS}>
{translate('OnApplicationUpdate')}
</Label> :
null
}
{
!onGrab && !onDownload && !onRename && !onHealthIssue && !onDelete && !onApplicationUpdate ?
<Label
kind={kinds.DISABLED}
outline={true}
>
Disabled
</Label>
{translate('Disabled')}
</Label> :
null
}
<EditNotificationModalConnector
@@ -161,12 +172,14 @@ Notification.propTypes = {
onRename: PropTypes.bool.isRequired,
onDelete: PropTypes.bool.isRequired,
onHealthIssue: PropTypes.bool.isRequired,
onApplicationUpdate: PropTypes.bool.isRequired,
supportsOnGrab: PropTypes.bool.isRequired,
supportsOnDownload: PropTypes.bool.isRequired,
supportsOnDelete: PropTypes.bool.isRequired,
supportsOnUpgrade: PropTypes.bool.isRequired,
supportsOnRename: PropTypes.bool.isRequired,
supportsOnHealthIssue: PropTypes.bool.isRequired,
supportsOnApplicationUpdate: PropTypes.bool.isRequired,
onConfirmDeleteNotification: PropTypes.func.isRequired
};

View File

@@ -16,8 +16,10 @@ function NotificationEventItems(props) {
const {
onHealthIssue,
onApplicationUpdate,
supportsOnHealthIssue,
includeHealthWarnings
includeHealthWarnings,
supportsOnApplicationUpdate
} = item;
return (
@@ -53,6 +55,17 @@ function NotificationEventItems(props) {
/>
</div>
}
<div>
<FormInputGroup
type={inputTypes.CHECK}
name="onApplicationUpdate"
helpText={translate('OnApplicationUpdateHelpText')}
isDisabled={!supportsOnApplicationUpdate.value}
{...onApplicationUpdate}
onChange={onInputChange}
/>
</div>
</div>
</div>
</FormGroup>

View File

@@ -67,7 +67,7 @@ function TagDetailsModalContent(props) {
{
!!indexerProxies.length &&
<FieldSet legend={translate('Indexer Proxies')}>
<FieldSet legend={translate('IndexerProxies')}>
{
indexerProxies.map((item) => {
return (

View File

@@ -106,6 +106,7 @@ export default {
selectedSchema.onDownload = selectedSchema.supportsOnDownload;
selectedSchema.onUpgrade = selectedSchema.supportsOnUpgrade;
selectedSchema.onRename = selectedSchema.supportsOnRename;
selectedSchema.onApplicationUpdate = selectedSchema.supportsOnApplicationUpdate;
return selectedSchema;
});

View File

@@ -199,7 +199,7 @@ class QueuedTaskRow extends Component {
</span>
{
clientUserAgent ?
<span className={styles.userAgent} title="User-Agent provided by the app that called the API">
<span className={styles.userAgent} title={translate('UserAgentProvidedByTheAppThatCalledTheAPI')}>
from: {clientUserAgent}
</span> :
null

View File

@@ -6,8 +6,8 @@
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<!-- Chrome, Opera, and Firefox OS -->
<meta name="theme-color" content="#3a3f51" />
<!-- Chrome, Safari, Opera, and Firefox OS -->
<meta name="theme-color" content="#e66001" />
<!-- Windows Phone -->
<meta name="msapplication-navbutton-color" content="#3a3f51" />

View File

@@ -6,8 +6,8 @@
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<!-- Chrome, Opera, and Firefox OS -->
<meta name="theme-color" content="#464b51" />
<!-- Chrome, Safari, Opera, and Firefox OS -->
<meta name="theme-color" content="#e66001" />
<!-- Windows Phone -->
<meta name="msapplication-navbutton-color" content="#464b51" />

View File

@@ -229,11 +229,6 @@ namespace NzbDrone.Common.Test.Http
[Test]
public void should_follow_redirects_to_https()
{
if (typeof(TDispatcher) == typeof(ManagedHttpDispatcher) && PlatformInfo.IsMono)
{
Assert.Ignore("Will fail on tls1.2 via managed dispatcher, ignore.");
}
var request = new HttpRequestBuilder($"https://{_httpBinHost}/redirect-to")
.AddQueryParam("url", $"https://radarr.video/")
.Build();

View File

@@ -258,6 +258,11 @@ namespace NzbDrone.Common.Extensions
return appFolderInfo.AppDataFolder;
}
public static string GetDataProtectionPath(this IAppFolderInfo appFolderInfo)
{
return Path.Combine(GetAppDataPath(appFolderInfo), "asp");
}
public static string GetLogFolder(this IAppFolderInfo appFolderInfo)
{
return Path.Combine(GetAppDataPath(appFolderInfo), "logs");

View File

@@ -34,19 +34,10 @@ namespace NzbDrone.Common.Http.Dispatchers
{
var webRequest = (HttpWebRequest)WebRequest.Create((Uri)request.Url);
if (PlatformInfo.IsMono)
{
// On Mono GZipStream/DeflateStream leaks memory if an exception is thrown, use an intermediate buffer in that case.
webRequest.AutomaticDecompression = DecompressionMethods.None;
webRequest.Headers.Add("Accept-Encoding", "gzip");
}
else
{
// Deflate is not a standard and could break depending on implementation.
// we should just stick with the more compatible Gzip
//http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net
webRequest.AutomaticDecompression = DecompressionMethods.GZip;
}
// Deflate is not a standard and could break depending on implementation.
// we should just stick with the more compatible Gzip
//http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net
webRequest.AutomaticDecompression = DecompressionMethods.GZip;
webRequest.Method = request.Method.ToString();
webRequest.UserAgent = _userAgentBuilder.GetUserAgent(request.UseSimplifiedUserAgent);
@@ -127,19 +118,6 @@ namespace NzbDrone.Common.Http.Dispatchers
try
{
data = await responseStream.ToBytes();
if (PlatformInfo.IsMono && httpWebResponse.ContentEncoding == "gzip")
{
using (var compressedStream = new MemoryStream(data))
using (var gzip = new GZipStream(compressedStream, CompressionMode.Decompress))
using (var decompressedStream = new MemoryStream())
{
gzip.CopyTo(decompressedStream);
data = decompressedStream.ToArray();
}
httpWebResponse.Headers.Remove("Content-Encoding");
}
}
catch (Exception ex)
{

View File

@@ -91,7 +91,9 @@ namespace NzbDrone.Common.Http
request.ContentData = null;
}
response = await ExecuteRequestAsync(request, cookieContainer);
var redirectContainer = HandleRedirectCookies(request, response);
response = await ExecuteRequestAsync(request, redirectContainer);
}
while (response.HasHttpRedirect);
}
@@ -162,6 +164,41 @@ namespace NzbDrone.Common.Http
return response;
}
private CookieContainer HandleRedirectCookies(HttpRequest request, HttpResponse response)
{
var sourceContainer = new CookieContainer();
var responseCookies = response.GetCookies();
if (responseCookies.Count != 0)
{
foreach (var pair in responseCookies)
{
Cookie cookie;
if (pair.Value == null)
{
cookie = new Cookie(pair.Key, "", "/")
{
Expires = DateTime.Now.AddDays(-1)
};
}
else
{
cookie = new Cookie(pair.Key, pair.Value, "/")
{
// Use Now rather than UtcNow to work around Mono cookie expiry bug.
// See https://gist.github.com/ta264/7822b1424f72e5b4c961
Expires = DateTime.Now.AddHours(1)
};
}
sourceContainer.Add((Uri)request.Url, cookie);
}
}
return sourceContainer;
}
private CookieContainer InitializeRequestCookies(HttpRequest request)
{
lock (_cookieContainerCache)

View File

@@ -11,21 +11,19 @@ namespace NzbDrone.Common.Http
{
private static readonly Regex RegexSetCookie = new Regex("^(.*?)=(.*?)(?:;|$)", RegexOptions.Compiled);
public HttpResponse(HttpRequest request, HttpHeader headers, CookieCollection cookies, byte[] binaryData, long elapsedTime = 0, HttpStatusCode statusCode = HttpStatusCode.OK)
public HttpResponse(HttpRequest request, HttpHeader headers, byte[] binaryData, long elapsedTime = 0, HttpStatusCode statusCode = HttpStatusCode.OK)
{
Request = request;
Headers = headers;
Cookies = cookies;
ResponseData = binaryData;
StatusCode = statusCode;
ElapsedTime = elapsedTime;
}
public HttpResponse(HttpRequest request, HttpHeader headers, CookieCollection cookies, string content, long elapsedTime = 0, HttpStatusCode statusCode = HttpStatusCode.OK)
public HttpResponse(HttpRequest request, HttpHeader headers, string content, long elapsedTime = 0, HttpStatusCode statusCode = HttpStatusCode.OK)
{
Request = request;
Headers = headers;
Cookies = cookies;
ResponseData = Headers.GetEncodingFromContentType().GetBytes(content);
_content = content;
StatusCode = statusCode;
@@ -34,7 +32,6 @@ namespace NzbDrone.Common.Http
public HttpRequest Request { get; private set; }
public HttpHeader Headers { get; private set; }
public CookieCollection Cookies { get; private set; }
public HttpStatusCode StatusCode { get; private set; }
public long ElapsedTime { get; private set; }
public byte[] ResponseData { get; private set; }
@@ -92,9 +89,14 @@ namespace NzbDrone.Common.Http
{
var result = new Dictionary<string, string>();
foreach (Cookie cookie in Cookies)
var setCookieHeaders = CookieUtil.CookieHeaderToDictionary();
foreach (var cookie in setCookieHeaders)
{
result[cookie.Name] = cookie.Value;
var match = RegexSetCookie.Match(cookie);
if (match.Success)
{
result[match.Groups[1].Value] = match.Groups[2].Value;
}
}
return result;

View File

@@ -38,16 +38,6 @@ namespace NzbDrone.Common.Instrumentation
return;
}
if (PlatformInfo.IsMono)
{
if ((exception is TypeInitializationException && exception.InnerException is DllNotFoundException) ||
exception is DllNotFoundException)
{
Logger.Debug(exception, "Minor Fail: " + exception.Message);
return;
}
}
Console.WriteLine("EPIC FAIL: {0}", exception);
Logger.Fatal(exception, "EPIC FAIL.");
}

View File

@@ -106,13 +106,6 @@ namespace NzbDrone.Common.Instrumentation.Sentry
o.Debug = false;
o.DiagnosticLevel = SentryLevel.Debug;
o.Release = BuildInfo.Release;
if (PlatformInfo.IsMono)
{
// Mono 6.0 broke GzipStream.WriteAsync
// TODO: Check specific version
o.RequestBodyCompressionLevel = System.IO.Compression.CompressionLevel.NoCompression;
}
o.BeforeSend = x => SentryCleanser.CleanseEvent(x);
o.BeforeBreadcrumb = x => SentryCleanser.CleanseBreadcrumb(x);
o.Environment = BuildInfo.Branch;
@@ -155,7 +148,7 @@ namespace NzbDrone.Common.Instrumentation.Sentry
{
scope.SetTag("is_docker", $"{osInfo.IsDocker}");
if (osInfo.Name != null && PlatformInfo.IsMono)
if (osInfo.Name != null && !OsInfo.IsWindows)
{
// Sentry auto-detection of non-Windows platforms isn't that accurate on certain devices.
scope.Contexts.OperatingSystem.Name = osInfo.Name.FirstCharToUpper();

View File

@@ -366,11 +366,6 @@ namespace NzbDrone.Common.Processes
private (string Path, string Args) GetPathAndArgs(string path, string args)
{
if (PlatformInfo.IsMono && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
{
return ("mono", $"--debug {path} {args}");
}
if (OsInfo.IsWindows && path.EndsWith(".bat", StringComparison.InvariantCultureIgnoreCase))
{
return ("cmd.exe", $"/c {path} {args}");

View File

@@ -1,4 +1,4 @@
using System.Data;
using System.Data;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
@@ -38,6 +38,7 @@ namespace NzbDrone.Core.Test.Datastore.SqliteSchemaDumperTests
result.Name.Should().Be(tableName);
result.Columns.Count.Should().Be(1);
result.Columns.First().Name.Should().Be(columnName);
result.Columns.First().IsIdentity.Should().BeTrue();
}
[TestCase(@"CREATE INDEX TestIndex ON TestTable (MyId)", "TestIndex", "TestTable", "MyId")]

View File

@@ -5,6 +5,7 @@ using System.Threading.Tasks;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.Rarbg;
@@ -51,7 +52,7 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests
torrentInfo.Title.Should().Be("Sense8.S01E01.WEBRip.x264-FGT");
torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
torrentInfo.DownloadUrl.Should().Be("magnet:?xt=urn:btih:d8bde635f573acb390c7d7e7efc1556965fdc802&dn=Sense8.S01E01.WEBRip.x264-FGT&tr=http%3A%2F%2Ftracker.trackerfix.com%3A80%2Fannounce&tr=udp%3A%2F%2F9.rarbg.me%3A2710&tr=udp%3A%2F%2F9.rarbg.to%3A2710&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce");
torrentInfo.InfoUrl.Should().Be("https://torrentapi.org/redirect_to_info.php?token=i5cx7b9agd&p=8_6_4_4_5_6__d8bde635f5&app_id=Prowlarr");
torrentInfo.InfoUrl.Should().Be($"https://torrentapi.org/redirect_to_info.php?token=i5cx7b9agd&p=8_6_4_4_5_6__d8bde635f5&app_id={BuildInfo.AppName}");
torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2015-06-05 16:58:11 +0000").ToUniversalTime());
torrentInfo.Size.Should().Be(564198371);

View File

@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using FluentAssertions;
using FluentValidation.Results;
using NUnit.Framework;
using NzbDrone.Core.Notifications;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.NotificationTests
{
[TestFixture]
public class NotificationBaseFixture : TestBase
{
private class TestSetting : IProviderConfig
{
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult();
}
}
private class TestNotificationWithApplicationUpdate : NotificationBase<TestSetting>
{
public override string Name => "TestNotification";
public override string Link => "";
public override ValidationResult Test()
{
throw new NotImplementedException();
}
public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage)
{
TestLogger.Info("OnApplicationUpdate was called");
}
}
private class TestNotificationWithAllEvents : NotificationBase<TestSetting>
{
public override string Name => "TestNotification";
public override string Link => "";
public override ValidationResult Test()
{
throw new NotImplementedException();
}
public override void OnHealthIssue(NzbDrone.Core.HealthCheck.HealthCheck artist)
{
TestLogger.Info("OnHealthIssue was called");
}
public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage)
{
TestLogger.Info("OnApplicationUpdate was called");
}
}
private class TestNotificationWithNoEvents : NotificationBase<TestSetting>
{
public override string Name => "TestNotification";
public override string Link => "";
public override ValidationResult Test()
{
throw new NotImplementedException();
}
}
[Test]
public void should_support_all_if_implemented()
{
var notification = new TestNotificationWithAllEvents();
notification.SupportsOnHealthIssue.Should().BeTrue();
notification.SupportsOnApplicationUpdate.Should().BeTrue();
}
[Test]
public void should_support_none_if_none_are_implemented()
{
var notification = new TestNotificationWithNoEvents();
notification.SupportsOnHealthIssue.Should().BeFalse();
notification.SupportsOnApplicationUpdate.Should().BeFalse();
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections;
using NUnit.Framework;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.ParserTests
{
[TestFixture]
public class DateTimeRoutinesFixture : CoreTest
{
public static IEnumerable DateTimeTestCases
{
get
{
yield return new TestCaseData(@"Member since: 10-Feb-2008").Returns(new DateTime(2008, 2, 10, 0, 0, 0));
yield return new TestCaseData(@"Last Update: 18:16 11 Feb '08 ").Returns(new DateTime(2008, 2, 11, 18, 16, 0));
yield return new TestCaseData(@"date Tue, Feb 10, 2008 at 11:06 AM").Returns(new DateTime(2008, 2, 10, 11, 06, 0));
yield return new TestCaseData(@"see at 12/31/2007 14:16:32").Returns(new DateTime(2007, 12, 31, 14, 16, 32));
yield return new TestCaseData(@"sack finish 14:16:32 November 15 2008, 1-144 app").Returns(new DateTime(2008, 11, 15, 14, 16, 32));
yield return new TestCaseData(@"Genesis Message - Wed 04 Feb 08 - 19:40").Returns(new DateTime(2008, 2, 4, 19, 40, 0));
yield return new TestCaseData(@"The day 07/31/07 14:16:32 is ").Returns(new DateTime(2007, 7, 31, 14, 16, 32));
yield return new TestCaseData(@"Shipping is on us until December 24, 2008 within the U.S. ").Returns(new DateTime(2008, 12, 24, 0, 0, 0));
yield return new TestCaseData(@" 2008 within the U.S. at 14:16:32").Returns(new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 14, 16, 32));
yield return new TestCaseData(@"5th November, 1994, 8:15:30 pm").Returns(new DateTime(1994, 11, 5, 20, 15, 30));
yield return new TestCaseData(@"7 boxes January 31 , 14:16:32.").Returns(new DateTime(DateTime.Now.Year, 1, 31, 14, 16, 32));
yield return new TestCaseData(@"the blue sky of Sept 30th 2008 14:16:32").Returns(new DateTime(2008, 9, 30, 14, 16, 32));
yield return new TestCaseData(@" e.g. 1997-07-16T19:20:30+01:00").Returns(new DateTime(1997, 7, 16, 19, 20, 30));
yield return new TestCaseData(@"Apr 1st, 2008 14:16:32 tufa 6767").Returns(new DateTime(2008, 4, 1, 14, 16, 32));
yield return new TestCaseData(@"wait for 07/31/07 14:16:32").Returns(new DateTime(2007, 7, 31, 14, 16, 32));
yield return new TestCaseData(@"later 12.31.08 and before 1.01.09").Returns(new DateTime(2008, 12, 31, 0, 0, 0));
yield return new TestCaseData(@"Expires: Sept 30th 2008 14:16:32").Returns(new DateTime(2008, 9, 30, 14, 16, 32));
yield return new TestCaseData(@"Offer expires Apr 1st, 2007, 14:16:32").Returns(new DateTime(2007, 4, 1, 14, 16, 32));
yield return new TestCaseData(@"Expires 14:16:32 January 31.").Returns(new DateTime(DateTime.Now.Year, 1, 31, 14, 16, 32));
yield return new TestCaseData(@"Expires 14:16:32 January 31-st.").Returns(new DateTime(DateTime.Now.Year, 1, 31, 14, 16, 32));
yield return new TestCaseData(@"Expires 23rd January 2010.").Returns(new DateTime(2010, 1, 23, 0, 0, 0));
yield return new TestCaseData(@"Expires January 22nd, 2010.").Returns(new DateTime(2010, 1, 22, 0, 0, 0));
yield return new TestCaseData(@"Expires DEC 22, 2010.").Returns(new DateTime(2010, 12, 22, 0, 0, 0));
yield return new TestCaseData(@"Version: 1.0.0.692 6/1/2010 2:28:04 AM ").Returns(new DateTime(2010, 6, 1, 2, 28, 4));
yield return new TestCaseData(@"Version: 1.0.0.692 04/21/11 12:30am ").Returns(new DateTime(2011, 4, 21, 00, 30, 00));
yield return new TestCaseData(@"Version: 1.0.0.692 04/21/11 12:30pm ").Returns(new DateTime(2011, 4, 21, 12, 30, 00));
yield return new TestCaseData(@"Version: Thu Aug 06 22:32:15 MDT 2009 ").Returns(new DateTime(2009, 8, 6, 22, 32, 15));
}
}
[TestCaseSource("DateTimeTestCases")]
public DateTime should_parse_date(string date)
{
DateTimeRoutines.TryParseDateOrTime(date, DateTimeRoutines.DateTimeFormat.USDate, out var parsedDateTime);
return parsedDateTime.DateTime;
}
}
}

View File

@@ -23,6 +23,7 @@ namespace NzbDrone.Core.Annotations
public string Section { get; set; }
public HiddenType Hidden { get; set; }
public PrivacyLevel Privacy { get; set; }
public string Placeholder { get; set; }
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]

View File

@@ -23,8 +23,6 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
public LazyLibrarianSettings()
{
ProwlarrUrl = "http://localhost:9696";
BaseUrl = "http://localhost:5299";
SyncCategories = new[]
{
NewznabStandardCategory.AudioAudiobook.Id,
@@ -38,10 +36,10 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
};
}
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as LazyLibrarian sees it, including http(s)://, port, and urlbase if needed")]
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as LazyLibrarian sees it, including http(s)://, port, and urlbase if needed", Placeholder = "http://localhost:9696")]
public string ProwlarrUrl { get; set; }
[FieldDefinition(1, Label = "LazyLibrarian Server", HelpText = "URL used to connect to LazyLibrarian server, including http(s)://, port, and urlbase if required")]
[FieldDefinition(1, Label = "LazyLibrarian Server", HelpText = "URL used to connect to LazyLibrarian server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:5299")]
public string BaseUrl { get; set; }
[FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by LazyLibrarian in Settings/Web Interface")]

View File

@@ -133,12 +133,19 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
{
return new ValidationFailure("ApiKey", status.Error.Message);
}
var indexers = GetIndexers(settings);
}
catch (HttpException ex)
{
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("BaseUrl", "Unable to complete application test");
}
catch (LazyLibrarianException ex)
{
_logger.Error(ex, "Connection test failed");
return new ValidationFailure("", ex.Message);
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message");

View File

@@ -22,15 +22,13 @@ namespace NzbDrone.Core.Applications.Lidarr
public LidarrSettings()
{
ProwlarrUrl = "http://localhost:9696";
BaseUrl = "http://localhost:8686";
SyncCategories = new[] { 3000, 3010, 3030, 3040, 3050, 3060 };
}
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Lidarr sees it, including http(s)://, port, and urlbase if needed")]
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Lidarr sees it, including http(s)://, port, and urlbase if needed", Placeholder = "http://localhost:9696")]
public string ProwlarrUrl { get; set; }
[FieldDefinition(1, Label = "Lidarr Server", HelpText = "URL used to connect to Lidarr server, including http(s)://, port, and urlbase if required")]
[FieldDefinition(1, Label = "Lidarr Server", HelpText = "URL used to connect to Lidarr server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:8686")]
public string BaseUrl { get; set; }
[FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Lidarr in Settings/General")]

View File

@@ -23,15 +23,13 @@ namespace NzbDrone.Core.Applications.Mylar
public MylarSettings()
{
ProwlarrUrl = "http://localhost:9696";
BaseUrl = "http://localhost:8090";
SyncCategories = new[] { NewznabStandardCategory.BooksComics.Id };
}
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Mylar sees it, including http(s)://, port, and urlbase if needed")]
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Mylar sees it, including http(s)://, port, and urlbase if needed", Placeholder = "http://localhost:9696")]
public string ProwlarrUrl { get; set; }
[FieldDefinition(1, Label = "Mylar Server", HelpText = "URL used to connect to Mylar server, including http(s)://, port, and urlbase if required")]
[FieldDefinition(1, Label = "Mylar Server", HelpText = "URL used to connect to Mylar server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:8090")]
public string BaseUrl { get; set; }
[FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Mylar in Settings/Web Interface")]

View File

@@ -133,12 +133,19 @@ namespace NzbDrone.Core.Applications.Mylar
{
return new ValidationFailure("ApiKey", status.Error.Message);
}
var indexers = GetIndexers(settings);
}
catch (HttpException ex)
{
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("BaseUrl", "Unable to complete application test");
}
catch (MylarException ex)
{
_logger.Error(ex, "Connection test failed");
return new ValidationFailure("", ex.Message);
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message");

View File

@@ -23,15 +23,13 @@ namespace NzbDrone.Core.Applications.Radarr
public RadarrSettings()
{
ProwlarrUrl = "http://localhost:9696";
BaseUrl = "http://localhost:7878";
SyncCategories = new[] { 2000, 2010, 2020, 2030, 2040, 2045, 2050, 2060, 2070, 2080 };
}
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Radarr sees it, including http(s)://, port, and urlbase if needed")]
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Radarr sees it, including http(s)://, port, and urlbase if needed", Placeholder = "http://localhost:9696")]
public string ProwlarrUrl { get; set; }
[FieldDefinition(1, Label = "Radarr Server", HelpText = "URL used to connect to Radarr server, including http(s)://, port, and urlbase if required")]
[FieldDefinition(1, Label = "Radarr Server", HelpText = "URL used to connect to Radarr server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:7878")]
public string BaseUrl { get; set; }
[FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Radarr in Settings/General")]

View File

@@ -23,15 +23,13 @@ namespace NzbDrone.Core.Applications.Readarr
public ReadarrSettings()
{
ProwlarrUrl = "http://localhost:9696";
BaseUrl = "http://localhost:8787";
SyncCategories = new[] { 3030, 7000, 7010, 7020, 7030, 7040, 7050, 7060 };
}
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Readarr sees it, including http(s)://, port, and urlbase if needed")]
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Readarr sees it, including http(s)://, port, and urlbase if needed", Placeholder = "http://localhost:9696")]
public string ProwlarrUrl { get; set; }
[FieldDefinition(1, Label = "Readarr Server", HelpText = "URL used to connect to Readarr server, including http(s)://, port, and urlbase if required")]
[FieldDefinition(1, Label = "Readarr Server", HelpText = "URL used to connect to Readarr server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:8787")]
public string BaseUrl { get; set; }
[FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Readarr in Settings/General")]

View File

@@ -22,16 +22,14 @@ namespace NzbDrone.Core.Applications.Sonarr
public SonarrSettings()
{
ProwlarrUrl = "http://localhost:9696";
BaseUrl = "http://localhost:8989";
SyncCategories = new[] { 5000, 5010, 5020, 5030, 5040, 5045, 5050 };
AnimeSyncCategories = new[] { 5070 };
}
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Sonarr sees it, including http(s)://, port, and urlbase if needed")]
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Sonarr sees it, including http(s)://, port, and urlbase if needed", Placeholder = "http://localhost:9696")]
public string ProwlarrUrl { get; set; }
[FieldDefinition(1, Label = "Sonarr Server", HelpText = "URL used to connect to Sonarr server, including http(s)://, port, and urlbase if required")]
[FieldDefinition(1, Label = "Sonarr Server", HelpText = "URL used to connect to Sonarr server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:8989")]
public string BaseUrl { get; set; }
[FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Sonarr in Settings/General")]

View File

@@ -0,0 +1,14 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(014)]
public class add_on_update_to_notifications : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("Notifications").AddColumn("OnApplicationUpdate").AsBoolean().WithDefaultValue(false);
}
}
}

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using FluentMigrator.Model;
using FluentMigrator.Runner.Processors.SQLite;
@@ -66,6 +67,24 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
if (columnReader.Read() == SqliteSyntaxReader.TokenType.StringToken)
{
if (columnReader.ValueToUpper == "PRIMARY")
{
columnReader.SkipTillToken(SqliteSyntaxReader.TokenType.ListStart);
if (columnReader.Read() == SqliteSyntaxReader.TokenType.Identifier)
{
var pk = table.Columns.First(v => v.Name == columnReader.Value);
pk.IsPrimaryKey = true;
pk.IsNullable = true;
pk.IsUnique = true;
if (columnReader.Buffer.ToUpperInvariant().Contains("AUTOINCREMENT"))
{
pk.IsIdentity = true;
}
continue;
}
}
if (columnReader.ValueToUpper == "CONSTRAINT" ||
columnReader.ValueToUpper == "PRIMARY" || columnReader.ValueToUpper == "UNIQUE" ||
columnReader.ValueToUpper == "CHECK" || columnReader.ValueToUpper == "FOREIGN")

View File

@@ -63,7 +63,8 @@ namespace NzbDrone.Core.Datastore
Mapper.Entity<NotificationDefinition>("Notifications").RegisterModel()
.Ignore(x => x.ImplementationName)
.Ignore(i => i.SupportsOnHealthIssue);
.Ignore(i => i.SupportsOnHealthIssue)
.Ignore(i => i.SupportsOnApplicationUpdate);
Mapper.Entity<IndexerProxyDefinition>("IndexerProxies").RegisterModel()
.Ignore(x => x.ImplementationName);

View File

@@ -113,7 +113,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
var url = request.Url.ToString();
var userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36";
var maxTimeout = 60000;
var maxTimeout = Settings.RequestTimeout * 1000;
if (request.Method == HttpMethod.GET)
{

View File

@@ -1,4 +1,5 @@
using FluentValidation;
using NLog.Config;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Validation;
@@ -9,6 +10,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
public FlareSolverrSettingsValidator()
{
RuleFor(c => c.Host).NotEmpty();
RuleFor(c => c.RequestTimeout).InclusiveBetween(1, 180);
}
}
@@ -19,11 +21,15 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
public FlareSolverrSettings()
{
Host = "http://localhost:8191/";
RequestTimeout = 60;
}
[FieldDefinition(0, Label = "Host")]
public string Host { get; set; }
[FieldDefinition(2, Label = "Request Timeout", Advanced = true, HelpText = "FlareSolverr maxTimeout Request Parameter", Unit = "seconds")]
public int RequestTimeout { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -10,6 +10,7 @@ namespace NzbDrone.Core.IndexerSearch.Definitions
public int? TmdbId { get; set; }
public int? TraktId { get; set; }
public int? Year { get; set; }
public string Genre { get; set; }
public override bool RssSearch
{
@@ -64,6 +65,11 @@ namespace NzbDrone.Core.IndexerSearch.Definitions
builder = builder.Append($" TraktId:[{TraktId}]");
}
if (Genre.IsNotNullOrWhiteSpace())
{
builder = builder.Append($" Genre:[{Genre}]");
}
return builder.ToString().Trim();
}
}

View File

@@ -7,6 +7,8 @@ namespace NzbDrone.Core.IndexerSearch.Definitions
public string Album { get; set; }
public string Artist { get; set; }
public string Label { get; set; }
public string Genre { get; set; }
public int? Year { get; set; }
public override bool RssSearch
{

View File

@@ -16,6 +16,7 @@ namespace NzbDrone.Core.IndexerSearch.Definitions
public int? RId { get; set; }
public int? TvMazeId { get; set; }
public int? TraktId { get; set; }
public int? TmdbId { get; set; }
public string SanitizedTvSearchString => (SanitizedSearchTerm + " " + EpisodeSearchString).Trim();
public string EpisodeSearchString => GetEpisodeSearchString();
@@ -74,6 +75,11 @@ namespace NzbDrone.Core.IndexerSearch.Definitions
builder.Append($" TraktId:[{TraktId}]");
}
if (TmdbId.HasValue)
{
builder.Append($" TmdbId:[{TmdbId}]");
}
builder = builder.Append(searchEpisodeTerm);
return builder.ToString().Trim();
}

View File

@@ -89,6 +89,8 @@ namespace NzbDrone.Core.IndexerSearch
new XAttribute("type", protocol == DownloadProtocol.Torrent ? "application/x-bittorrent" : "application/x-nzb")),
r.Categories == null ? null : from c in r.Categories select GetNabElement("category", c.Id, protocol),
r.IndexerFlags == null ? null : from f in r.IndexerFlags select GetNabElement("tag", f.Name, protocol),
r.Languages == null ? null : from c in r.Languages select GetNabElement("language", c.Id, protocol),
r.Subs == null ? null : from c in r.Subs select GetNabElement("subs", c.Id, protocol),
GetNabElement("rageid", r.TvRageId, protocol),
GetNabElement("tvdbid", r.TvdbId, protocol),
GetNabElement("imdb", r.ImdbId.ToString("D7"), protocol),

View File

@@ -60,6 +60,7 @@ namespace NzbDrone.Core.IndexerSearch
searchSpec.TmdbId = request.tmdbid;
searchSpec.TraktId = request.traktid;
searchSpec.Year = request.year;
searchSpec.Genre = request.genre;
return new NewznabResults { Releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) };
}
@@ -71,6 +72,8 @@ namespace NzbDrone.Core.IndexerSearch
searchSpec.Artist = request.artist;
searchSpec.Album = request.album;
searchSpec.Label = request.label;
searchSpec.Genre = request.genre;
searchSpec.Year = request.year;
return new NewznabResults { Releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) };
}
@@ -84,6 +87,7 @@ namespace NzbDrone.Core.IndexerSearch
searchSpec.TvdbId = request.tvdbid;
searchSpec.ImdbId = request.imdbid;
searchSpec.TraktId = request.traktid;
searchSpec.TmdbId = request.tmdbid;
searchSpec.RId = request.rid;
searchSpec.TvMazeId = request.tvmazeid;

View File

@@ -8,7 +8,7 @@ using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete]
[Obsolete("Moved to YML for Cardigann v3")]
public class Aither : Unit3dBase
{
public override string Name => "Aither";

View File

@@ -30,7 +30,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Language => "ru-RU";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPublic;
public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate;
public override IndexerCapabilities Capabilities => SetCapabilities();
public Anidub(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)

View File

@@ -17,6 +17,7 @@ using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete("Moved to YML for Cardigann v3")]
public class Anilibria : TorrentIndexerBase<AnilibriaSettings>
{
public override string Name => "Anilibria";

View File

@@ -106,7 +106,37 @@ namespace NzbDrone.Core.Indexers.Definitions
{
}
private IEnumerable<IndexerRequest> GetPagedRequests(string searchType, string term, int[] categories)
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
=> GetRequestWithSearchType(searchCriteria, "anime");
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
=> GetRequestWithSearchType(searchCriteria, "music");
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
=> GetRequestWithSearchType(searchCriteria, "anime");
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
=> GetRequestWithSearchType(searchCriteria, "anime");
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
=> GetRequestWithSearchType(searchCriteria, "anime");
private IndexerPageableRequestChain GetRequestWithSearchType(SearchCriteriaBase searchCriteria, string searchType)
{
var pageableRequests = new IndexerPageableRequestChain();
// TODO: Remove this once Prowlarr has proper support for non Pageable Indexers and can tell Sonarr that indexer doesn't support pagination in a proper way, for now just return empty release list on all request containing an offset
if (searchCriteria.Offset is > 0)
{
return pageableRequests;
}
pageableRequests.Add(GetRequest(searchType, searchCriteria.SanitizedSearchTerm, searchCriteria.Categories));
return pageableRequests;
}
private IEnumerable<IndexerRequest> GetRequest(string searchType, string term, int[] categories)
{
var searchUrl = string.Format("{0}/scrape.php", Settings.BaseUrl.TrimEnd('/'));
@@ -135,51 +165,6 @@ namespace NzbDrone.Core.Indexers.Definitions
yield return request;
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests("anime", searchCriteria.SanitizedSearchTerm, searchCriteria.Categories));
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests("music", searchCriteria.SanitizedSearchTerm, searchCriteria.Categories));
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests("anime", searchCriteria.SanitizedSearchTerm, searchCriteria.Categories));
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests("anime", searchCriteria.SanitizedSearchTerm, searchCriteria.Categories));
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests("anime", searchCriteria.SanitizedSearchTerm, searchCriteria.Categories));
return pageableRequests;
}
public Func<IDictionary<string, string>> GetCookies { get; set; }
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }

View File

@@ -8,7 +8,7 @@ using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete]
[Obsolete("Moved to YML for Cardigann v3")]
public class AnimeWorld : Unit3dBase
{
public override string Name => "AnimeWorld";

View File

@@ -36,11 +36,11 @@ namespace NzbDrone.Core.Indexers.Definitions
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId
}
};

View File

@@ -77,6 +77,10 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
{
parameters.Add("imdb", searchCriteria.FullImdbId);
}
else if (searchCriteria.TmdbId.HasValue)
{
parameters.Add("tmdb", searchCriteria.TmdbId.Value.ToString());
}
else
{
parameters.Add("search", GetSearchTerm(searchCriteria.SanitizedSearchTerm).Trim());
@@ -105,6 +109,12 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace())
{
parameters.Add("imdb", searchCriteria.FullImdbId);
parameters.Add("search", GetSearchTerm(searchCriteria.EpisodeSearchString).Trim());
}
else if (searchCriteria.TvdbId.HasValue)
{
parameters.Add("tvdb", searchCriteria.TvdbId.Value.ToString());
parameters.Add("search", GetSearchTerm(searchCriteria.EpisodeSearchString).Trim());
}
else
{

View File

@@ -178,7 +178,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{ "searchtags", "" },
{ "tags_type", "0" },
{ "action", "basic" },
{ "searchstr", term }
{ "searchstr", term.Replace(".", " ") }
};
var catList = Capabilities.Categories.MapTorznabCapsToTrackers(categories);

View File

@@ -8,7 +8,7 @@ using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete]
[Obsolete("Moved to YML for Cardigann v3")]
public class Blutopia : Unit3dBase
{
public override string Name => "Blutopia";

View File

@@ -128,7 +128,12 @@ namespace NzbDrone.Core.Indexers.Cardigann
IndexerUrls = definition.Links.ToArray(),
Settings = new CardigannSettings { DefinitionFile = definition.File },
Protocol = DownloadProtocol.Torrent,
Privacy = definition.Type == "private" ? IndexerPrivacy.Private : IndexerPrivacy.Public,
Privacy = definition.Type switch
{
"private" => IndexerPrivacy.Private,
"public" => IndexerPrivacy.Public,
_ => IndexerPrivacy.SemiPrivate
},
SupportsRss = SupportsRss,
SupportsSearch = SupportsSearch,
SupportsRedirect = SupportsRedirect,

View File

@@ -633,7 +633,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
var date = DateTimeUtil.ParseDateTimeGoLang(data, layout);
data = date.ToString(DateTimeUtil.Rfc1123ZPattern);
}
catch (FormatException ex)
catch (InvalidDateException ex)
{
_logger.Debug(ex.Message);
}

View File

@@ -22,7 +22,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public class DanishBytes : TorrentIndexerBase<DanishBytesSettings>
{
public override string Name => "DanishBytes";
public override string[] IndexerUrls => new string[] { "https://danishbytes.org/" };
public override string[] IndexerUrls => new string[] { "https://danishbytes.club/" };
public override string Description => "DanishBytes is a Private Danish Tracker";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;

View File

@@ -9,7 +9,7 @@ using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete]
[Obsolete("Moved to YML for Cardigann v3")]
public class DesiTorrents : Unit3dBase
{
public override string Name => "DesiTorrents";

View File

@@ -20,7 +20,7 @@ using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete]
[Obsolete("Moved to YML for Cardigann v3")]
public class DigitalCore : TorrentIndexerBase<DigitalCoreSettings>
{
public override string Name => "DigitalCore";

View File

@@ -52,6 +52,8 @@ namespace NzbDrone.Core.Indexers.Gazelle
foreach (var result in jsonResponse.Resource.Response.Results)
{
var posterUrl = GetPosterUrl(result.Cover);
if (result.Torrents != null)
{
foreach (var torrent in result.Torrents)
@@ -66,9 +68,11 @@ namespace NzbDrone.Core.Indexers.Gazelle
title += " [Cue]";
}
var infoUrl = GetInfoUrl(result.GroupId, id);
var release = new GazelleInfo()
{
Guid = string.Format("Gazelle-{0}", id),
Guid = infoUrl,
Title = WebUtility.HtmlDecode(title),
Container = torrent.Encoding,
Files = torrent.FileCount,
@@ -76,11 +80,14 @@ namespace NzbDrone.Core.Indexers.Gazelle
Codec = torrent.Format,
Size = long.Parse(torrent.Size),
DownloadUrl = GetDownloadUrl(id),
InfoUrl = GetInfoUrl(result.GroupId, id),
InfoUrl = infoUrl,
Seeders = int.Parse(torrent.Seeders),
Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders),
PublishDate = torrent.Time.ToUniversalTime(),
Scene = torrent.Scene,
PosterUrl = posterUrl,
DownloadVolumeFactor = torrent.IsFreeLeech || torrent.IsNeutralLeech || torrent.IsPersonalFreeLeech ? 0 : 1,
UploadVolumeFactor = torrent.IsNeutralLeech ? 0 : 1
};
var category = torrent.Category;
@@ -100,19 +107,23 @@ namespace NzbDrone.Core.Indexers.Gazelle
{
var id = result.TorrentId;
var groupName = WebUtility.HtmlDecode(result.GroupName);
var infoUrl = GetInfoUrl(result.GroupId, id);
var release = new GazelleInfo()
{
Guid = string.Format("Gazelle-{0}", id),
Guid = infoUrl,
Title = groupName,
Size = long.Parse(result.Size),
DownloadUrl = GetDownloadUrl(id),
InfoUrl = GetInfoUrl(result.GroupId, id),
InfoUrl = infoUrl,
Seeders = int.Parse(result.Seeders),
Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders),
Files = result.FileCount,
Grabs = result.Snatches,
PublishDate = DateTimeOffset.FromUnixTimeSeconds(result.GroupTime).UtcDateTime,
PosterUrl = posterUrl,
DownloadVolumeFactor = result.IsFreeLeech || result.IsNeutralLeech || result.IsPersonalFreeLeech ? 0 : 1,
UploadVolumeFactor = result.IsNeutralLeech ? 0 : 1
};
var category = result.Category;
@@ -147,7 +158,19 @@ namespace NzbDrone.Core.Indexers.Gazelle
return url.FullUri;
}
private string GetInfoUrl(string groupId, int torrentId)
protected virtual string GetPosterUrl(string cover)
{
if (!string.IsNullOrEmpty(cover))
{
return cover.StartsWith("http") ?
new HttpUri(cover).FullUri :
new HttpUri(_settings.BaseUrl).CombinePath(cover).FullUri;
}
return null;
}
protected virtual string GetInfoUrl(string groupId, int torrentId)
{
var url = new HttpUri(_settings.BaseUrl)
.CombinePath("/torrents.php")

View File

@@ -158,7 +158,7 @@ namespace NzbDrone.Core.Indexers.Definitions
};
// manually url encode parenthesis to prevent "hacking" detection
searchUrl += queryCollection.GetQueryString().Replace("(", "%28").Replace(")", "%29");
searchUrl += queryCollection.GetQueryString().Replace("(", "%28").Replace(")", "%29").Replace(".", " ");
var request = new IndexerRequest(searchUrl, HttpAccept.Rss);
@@ -178,7 +178,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
return pageableRequests;
}
@@ -187,7 +187,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId));
return pageableRequests;
}
@@ -196,7 +196,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
return pageableRequests;
}
@@ -205,7 +205,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
return pageableRequests;
}

View File

@@ -17,7 +17,7 @@ using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete]
[Obsolete("Moved to YML for Cardigann v3")]
public class InternetArchive : TorrentIndexerBase<InternetArchiveSettings>
{
public override string Name => "Internet Archive";

View File

@@ -15,7 +15,7 @@ using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete]
[Obsolete("Moved to YML for Cardigann v3")]
public class Milkie : TorrentIndexerBase<MilkieSettings>
{
public override string Name => "Milkie";

View File

@@ -88,7 +88,7 @@ namespace NzbDrone.Core.Indexers.Newznab
yield return GetDefinition("altHUB", GetSettings("https://althub.co.za"));
yield return GetDefinition("AnimeTosho (Usenet)", GetSettings("https://feed.animetosho.org"));
yield return GetDefinition("DOGnzb", GetSettings("https://api.dognzb.cr"));
yield return GetDefinition("DrunkenSlug", GetSettings("https://api.drunkenslug.com"));
yield return GetDefinition("DrunkenSlug", GetSettings("https://drunkenslug.com"));
yield return GetDefinition("GingaDADDY", GetSettings("https://www.gingadaddy.com"));
yield return GetDefinition("Miatrix", GetSettings("https://www.miatrix.com"));
yield return GetDefinition("Newz-Complex", GetSettings("https://newz-complex.org/www"));

View File

@@ -23,14 +23,6 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q, MusicSearchParam.Album, MusicSearchParam.Artist, MusicSearchParam.Label, MusicSearchParam.Year
@@ -45,8 +37,8 @@ namespace NzbDrone.Core.Indexers.Definitions
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.PC, "Applications");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Books, "E-Books");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.AudioAudiobook, "Audiobooks");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Movies, "E-Learning Videos");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.TV, "Comedy");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Other, "E-Learning Videos");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.Other, "Comedy");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.Books, "Comics");
return caps;

View File

@@ -142,6 +142,7 @@ namespace NzbDrone.Core.Indexers.Definitions
caps.Categories.AddCategoryMapping(1836, NewznabStandardCategory.XXX, "Сайтрипы 2019 (HD Video) / SiteRip's 2019 (HD Video)");
caps.Categories.AddCategoryMapping(1842, NewznabStandardCategory.XXX, "Сайтрипы 2020 (HD Video) / SiteRip's 2020 (HD Video)");
caps.Categories.AddCategoryMapping(1846, NewznabStandardCategory.XXX, "Сайтрипы 2021 (HD Video) / SiteRip's 2021 (HD Video)");
caps.Categories.AddCategoryMapping(1857, NewznabStandardCategory.XXX, "Сайтрипы 2022 (HD Video) / SiteRip's 2022 (HD Video)");
caps.Categories.AddCategoryMapping(1451, NewznabStandardCategory.XXX, "Сайтрипы 1991-2010 / SiteRip's 1991-2010");
caps.Categories.AddCategoryMapping(1788, NewznabStandardCategory.XXX, "Сайтрипы 2011-2012 / SiteRip's 2011-2012");
@@ -154,6 +155,7 @@ namespace NzbDrone.Core.Indexers.Definitions
caps.Categories.AddCategoryMapping(1837, NewznabStandardCategory.XXX, "Сайтрипы 2019 / SiteRip's 2019");
caps.Categories.AddCategoryMapping(1843, NewznabStandardCategory.XXX, "Сайтрипы 2020 / SiteRip's 2020");
caps.Categories.AddCategoryMapping(1847, NewznabStandardCategory.XXX, "Сайтрипы 2021 / SiteRip's 2021");
caps.Categories.AddCategoryMapping(1856, NewznabStandardCategory.XXX, "Сайтрипы 2022 / SiteRip's 2022");
caps.Categories.AddCategoryMapping(1707, NewznabStandardCategory.XXX, "Сцены из фильмов / Movie Scenes");
caps.Categories.AddCategoryMapping(284, NewznabStandardCategory.XXX, "Порноролики Разное / Clips (various)");

View File

@@ -1,6 +1,5 @@
using System.Collections.Generic;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Definitions.Avistaz;
using NzbDrone.Core.Messaging.Events;
@@ -36,11 +35,11 @@ namespace NzbDrone.Core.Indexers.Definitions
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId
},
MusicSearchParams = new List<MusicSearchParam>
{

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
@@ -103,7 +104,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
try
{
var request = new HttpRequestBuilder(Settings.BaseUrl.Trim('/'))
.Resource("/pubapi_v2.php?get_token=get_token")
.Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}")
.Accept(HttpAccept.Json)
.Build();

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Net;
using System.Text.RegularExpressions;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Parser.Model;
@@ -62,7 +63,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
torrentInfo.Title = torrent.title;
torrentInfo.Size = torrent.size;
torrentInfo.DownloadUrl = torrent.download;
torrentInfo.InfoUrl = torrent.info_page + "&app_id=Prowlarr";
torrentInfo.InfoUrl = $"{torrent.info_page}&app_id={BuildInfo.AppName}";
torrentInfo.PublishDate = torrent.pubdate.ToUniversalTime();
torrentInfo.Seeders = torrent.seeders;
torrentInfo.Peers = torrent.leechers + torrent.seeders;

View File

@@ -2,6 +2,7 @@ using System;
using Newtonsoft.Json.Linq;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
@@ -32,7 +33,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
{
var requestBuilder = new HttpRequestBuilder(baseUrl.Trim('/'))
.WithRateLimit(3.0)
.Resource("/pubapi_v2.php?get_token=get_token&app_id=Prowlarr")
.Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}")
.Accept(HttpAccept.Json);
if (settings.CaptchaToken.IsNotNullOrWhiteSpace())

View File

@@ -221,9 +221,11 @@ namespace NzbDrone.Core.Indexers.Definitions
title += " [Cue]";
}
var infoUrl = GetInfoUrl(result.GroupId, id);
GazelleInfo release = new GazelleInfo()
{
Guid = string.Format("Redacted-{0}", id),
Guid = infoUrl,
// Splice Title from info to avoid calling API again for every torrent.
Title = WebUtility.HtmlDecode(title),
@@ -232,7 +234,7 @@ namespace NzbDrone.Core.Indexers.Definitions
Codec = torrent.Format,
Size = long.Parse(torrent.Size),
DownloadUrl = GetDownloadUrl(id, torrent.CanUseToken),
InfoUrl = GetInfoUrl(result.GroupId, id),
InfoUrl = infoUrl,
Seeders = int.Parse(torrent.Seeders),
Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders),
PublishDate = torrent.Time.ToUniversalTime(),
@@ -240,6 +242,8 @@ namespace NzbDrone.Core.Indexers.Definitions
Freeleech = torrent.IsFreeLeech || torrent.IsPersonalFreeLeech,
Files = torrent.FileCount,
Grabs = torrent.Snatches,
DownloadVolumeFactor = torrent.IsFreeLeech || torrent.IsNeutralLeech || torrent.IsPersonalFreeLeech ? 0 : 1,
UploadVolumeFactor = torrent.IsNeutralLeech ? 0 : 1
};
var category = torrent.Category;
@@ -260,19 +264,23 @@ namespace NzbDrone.Core.Indexers.Definitions
else
{
var id = result.TorrentId;
var infoUrl = GetInfoUrl(result.GroupId, id);
GazelleInfo release = new GazelleInfo()
{
Guid = string.Format("Redacted-{0}", id),
Guid = infoUrl,
Title = WebUtility.HtmlDecode(result.GroupName),
Size = long.Parse(result.Size),
DownloadUrl = GetDownloadUrl(id, result.CanUseToken),
InfoUrl = GetInfoUrl(result.GroupId, id),
InfoUrl = infoUrl,
Seeders = int.Parse(result.Seeders),
Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders),
PublishDate = DateTimeOffset.FromUnixTimeSeconds(result.GroupTime).UtcDateTime,
Freeleech = result.IsFreeLeech || result.IsPersonalFreeLeech,
Files = result.FileCount,
Grabs = result.Snatches,
DownloadVolumeFactor = result.IsFreeLeech || result.IsNeutralLeech || result.IsPersonalFreeLeech ? 0 : 1,
UploadVolumeFactor = result.IsNeutralLeech ? 0 : 1
};
var category = result.Category;

View File

@@ -8,7 +8,7 @@ using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete]
[Obsolete("Moved to YML for Cardigann v3")]
public class ShareIsland : Unit3dBase
{
public override string Name => "ShareIsland";

View File

@@ -61,7 +61,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public override IParseIndexerResponse GetParser()
{
return new SpeedAppParser(Settings);
return new SpeedAppParser(Settings, Capabilities.Categories);
}
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
@@ -335,7 +335,7 @@ namespace NzbDrone.Core.Indexers.Definitions
}
}
var searchUrl = Settings.BaseUrl + "/api/torrent?" + qc.GetQueryString();
var searchUrl = Settings.BaseUrl + "/api/torrent?" + qc.GetQueryString(duplicateKeysIfMulti: true);
var request = new IndexerRequest(searchUrl, HttpAccept.Json);
@@ -347,13 +347,15 @@ namespace NzbDrone.Core.Indexers.Definitions
public class SpeedAppParser : IParseIndexerResponse
{
public SpeedAppSettings Settings { get; set; }
private readonly SpeedAppSettings _settings;
private readonly IndexerCapabilitiesCategories _categories;
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
public SpeedAppParser(SpeedAppSettings settings)
public SpeedAppParser(SpeedAppSettings settings, IndexerCapabilitiesCategories categories)
{
Settings = settings;
_settings = settings;
_categories = categories;
}
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
@@ -377,12 +379,12 @@ namespace NzbDrone.Core.Indexers.Definitions
Description = torrent.ShortDescription,
Size = torrent.Size,
ImdbId = ParseUtil.GetImdbID(torrent.ImdbId).GetValueOrDefault(),
DownloadUrl = $"{Settings.BaseUrl}/api/torrent/{torrent.Id}/download",
DownloadUrl = $"{_settings.BaseUrl}/api/torrent/{torrent.Id}/download",
PosterUrl = torrent.Poster,
InfoUrl = torrent.Url,
Grabs = torrent.TimesCompleted,
PublishDate = torrent.CreatedAt,
Categories = new List<IndexerCategory> { new (torrent.Category.Id, torrent.Category.Name), },
Categories = _categories.MapTrackerCatToNewznab(torrent.Category.Id.ToString()),
InfoHash = null,
Seeders = torrent.Seeders,
Peers = torrent.Leechers + torrent.Seeders,

View File

@@ -18,7 +18,7 @@ using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete]
[Obsolete("Moved to YML for Cardigann v3")]
public class SuperBits : TorrentIndexerBase<SuperBitsSettings>
{
public override string Name => "SuperBits";

View File

@@ -22,6 +22,7 @@ using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete("Remove per Site Request Prowlarr Issue 573")]
public class TVVault : TorrentIndexerBase<TVVaultSettings>
{
public override string Name => "TVVault";

View File

@@ -16,7 +16,7 @@ using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete]
[Obsolete("Moved to YML for Cardigann v3")]
public class ThePirateBay : TorrentIndexerBase<ThePirateBaySettings>
{
public override string Name => "ThePirateBay";

View File

@@ -20,7 +20,7 @@ using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete]
[Obsolete("Moved to YML for Cardigann v3")]
public class TorrentLeech : TorrentIndexerBase<TorrentLeechSettings>
{
public override string Name => "TorrentLeech";
@@ -281,7 +281,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var torrentId = row.fid.ToString();
var details = new Uri(_settings.BaseUrl + "torrent/" + torrentId);
var link = new Uri(_settings.BaseUrl + "download/" + torrentId + "/" + row.filename);
var publishDate = DateTime.ParseExact(row.addedTimestamp.ToString(), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
var publishDate = DateTime.ParseExact(row.addedTimestamp.ToString(), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
var seeders = (int)row.seeders;
var leechers = (int)row.leechers;
var grabs = (int)row.completed;

View File

@@ -18,7 +18,7 @@ using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete]
[Obsolete("Moved to YML for Cardigann v3")]
public class TorrentParadiseMl : TorrentIndexerBase<TorrentParadiseMlSettings>
{
public override string Name => "TorrentParadiseMl";

View File

@@ -21,6 +21,7 @@ using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete("Moved to YML for Cardigann v3")]
public class TorrentSeeds : TorrentIndexerBase<TorrentSeedsSettings>
{
public override string Name => "TorrentSeeds";

View File

@@ -18,7 +18,7 @@ using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete]
[Obsolete("Moved to YML for Cardigann v3")]
public class YTS : TorrentIndexerBase<YTSSettings>
{
public override string Name => "YTS";

View File

@@ -13,7 +13,9 @@ namespace NzbDrone.Core.Indexers
ImdbId,
TvdbId,
RId,
TvMazeId
TvMazeId,
TraktId,
TmdbId
}
public enum MovieSearchParam
@@ -24,6 +26,7 @@ namespace NzbDrone.Core.Indexers
ImdbTitle,
ImdbYear,
TraktId,
Genre
}
public enum MusicSearchParam
@@ -32,7 +35,8 @@ namespace NzbDrone.Core.Indexers
Album,
Artist,
Label,
Year
Year,
Genre
}
public enum SearchParam
@@ -65,12 +69,15 @@ namespace NzbDrone.Core.Indexers
public bool TvSearchTvdbAvailable => TvSearchParams.Contains(TvSearchParam.TvdbId);
public bool TvSearchTvRageAvailable => TvSearchParams.Contains(TvSearchParam.RId);
public bool TvSearchTvMazeAvailable => TvSearchParams.Contains(TvSearchParam.TvMazeId);
public bool TvSearchTraktAvailable => TvSearchParams.Contains(TvSearchParam.TraktId);
public bool TvSearchTmdbAvailable => TvSearchParams.Contains(TvSearchParam.TmdbId);
public List<MovieSearchParam> MovieSearchParams;
public bool MovieSearchAvailable => MovieSearchParams.Count > 0;
public bool MovieSearchImdbAvailable => MovieSearchParams.Contains(MovieSearchParam.ImdbId);
public bool MovieSearchTmdbAvailable => MovieSearchParams.Contains(MovieSearchParam.TmdbId);
public bool MovieSearchTraktAvailable => MovieSearchParams.Contains(MovieSearchParam.TraktId);
public bool MovieSearchGenreAvailable => MovieSearchParams.Contains(MovieSearchParam.Genre);
public List<MusicSearchParam> MusicSearchParams;
public bool MusicSearchAvailable => MusicSearchParams.Count > 0;
@@ -78,6 +85,7 @@ namespace NzbDrone.Core.Indexers
public bool MusicSearchArtistAvailable => MusicSearchParams.Contains(MusicSearchParam.Artist);
public bool MusicSearchLabelAvailable => MusicSearchParams.Contains(MusicSearchParam.Label);
public bool MusicSearchYearAvailable => MusicSearchParams.Contains(MusicSearchParam.Year);
public bool MusicSearchGenreAvailable => MusicSearchParams.Contains(MusicSearchParam.Genre);
public List<BookSearchParam> BookSearchParams;
public bool BookSearchAvailable => BookSearchParams.Count > 0;
@@ -284,6 +292,16 @@ namespace NzbDrone.Core.Indexers
parameters.Add("tvmazeid");
}
if (TvSearchTraktAvailable)
{
parameters.Add("traktid");
}
if (TvSearchTmdbAvailable)
{
parameters.Add("tmdbid");
}
return string.Join(",", parameters);
}
@@ -307,6 +325,16 @@ namespace NzbDrone.Core.Indexers
parameters.Add("tmdbid");
}
if (MovieSearchTraktAvailable)
{
parameters.Add("traktid");
}
if (MovieSearchGenreAvailable)
{
parameters.Add("genre");
}
return string.Join(",", parameters);
}
@@ -333,6 +361,11 @@ namespace NzbDrone.Core.Indexers
parameters.Add("year");
}
if (MusicSearchGenreAvailable)
{
parameters.Add("genre");
}
return string.Join(",", parameters);
}

View File

@@ -94,7 +94,12 @@ namespace NzbDrone.Core.Indexers
definition.Description = defFile.Description;
definition.Language = defFile.Language;
definition.Encoding = Encoding.GetEncoding(defFile.Encoding);
definition.Privacy = defFile.Type == "private" ? IndexerPrivacy.Private : IndexerPrivacy.Public;
definition.Privacy = defFile.Type switch
{
"private" => IndexerPrivacy.Private,
"public" => IndexerPrivacy.Public,
_ => IndexerPrivacy.SemiPrivate
};
definition.Capabilities = new IndexerCapabilities();
definition.Capabilities.ParseCardigannSearchModes(defFile.Caps.Modes);
definition.Capabilities.SupportsRawSearch = defFile.Caps.Allowrawsearch;

View File

@@ -3,7 +3,7 @@ namespace NzbDrone.Core.Indexers
public enum IndexerPrivacy
{
Public,
SemiPublic,
SemiPrivate,
Private
}
}

View File

@@ -61,6 +61,7 @@
"BypassProxyForLocalAddresses": "Bypass Proxy for Local Addresses",
"Cancel": "Cancel",
"CancelPendingTask": "Are you sure you want to cancel this pending task?",
"Categories": "Categories",
"Category": "Category",
"CertificateValidation": "Certificate Validation",
"CertificateValidationHelpText": "Change how strict HTTPS certification validation is",
@@ -69,7 +70,6 @@
"ClearHistory": "Clear History",
"ClearHistoryMessageText": "Are you sure you want to clear all Prowlarr history?",
"ClientPriority": "Client Priority",
"CloneIndexer": "Clone Indexer",
"CloneProfile": "Clone Profile",
"Close": "Close",
"CloseCurrentModal": "Close Current Modal",
@@ -88,7 +88,6 @@
"Date": "Date",
"Dates": "Dates",
"DBMigration": "DB Migration",
"DelayProfile": "Delay Profile",
"Delete": "Delete",
"DeleteApplication": "Delete Application",
"DeleteApplicationMessageText": "Are you sure you want to delete the application '{0}'?",
@@ -97,8 +96,6 @@
"DeleteBackupMessageText": "Are you sure you want to delete the backup '{0}'?",
"DeleteDownloadClient": "Delete Download Client",
"DeleteDownloadClientMessageText": "Are you sure you want to delete the download client '{0}'?",
"DeleteIndexer": "Delete Indexer",
"DeleteIndexerMessageText": "Are you sure you want to delete the indexer '{0}'?",
"DeleteIndexerProxy": "Delete Indexer Proxy",
"DeleteIndexerProxyMessageText": "Are you sure you want to delete the proxy '{0}'?",
"DeleteNotification": "Delete Notification",
@@ -113,35 +110,21 @@
"Docker": "Docker",
"Donations": "Donations",
"DownloadClient": "Download Client",
"DownloadClientCheckNoneAvailableMessage": "No download client is available",
"DownloadClientCheckUnableToCommunicateMessage": "Unable to communicate with {0}.",
"DownloadClients": "Download Clients",
"DownloadClientSettings": "Download Client Settings",
"DownloadClientsSettingsSummary": "Download clients configuration for integration into Prowlarr UI search",
"DownloadClientStatusCheckAllClientMessage": "All download clients are unavailable due to failures",
"DownloadClientStatusCheckSingleClientMessage": "Download clients unavailable due to failures: {0}",
"DownloadClientUnavailable": "Download client is unavailable",
"Downloading": "Downloading",
"Edit": "Edit",
"EditAppProfile": "Edit App Profile",
"EditIndexer": "Edit Indexer",
"Enable": "Enable",
"EnableAutoHelpText": "If enabled, Movies will be automatically added to Prowlarr from this list",
"EnableAutomaticAdd": "Enable Automatic Add",
"EnableAutomaticSearch": "Enable Automatic Search",
"EnableAutomaticSearchHelpText": "Will be used when automatic searches are performed via the UI or by Prowlarr",
"EnableAutomaticSearchHelpTextWarning": "Will be used when interactive search is used",
"EnableColorImpairedMode": "Enable Color-Impaired Mode",
"EnableColorImpairedModeHelpText": "Altered style to allow color-impaired users to better distinguish color coded information",
"EnableCompletedDownloadHandlingHelpText": "Automatically import completed downloads from download client",
"Enabled": "Enabled",
"EnabledHelpText": "Enable this list for use in Prowlarr",
"EnableHelpText": "Enable metadata file creation for this metadata type",
"EnableIndexer": "Enable Indexer",
"EnableInteractiveSearch": "Enable Interactive Search",
"EnableInteractiveSearchHelpText": "Will be used when interactive search is used",
"EnableInteractiveSearchHelpTextWarning": "Search is not supported with this indexer",
"EnableMediaInfoHelpText": "Extract video information such as resolution, runtime and codec information from files. This requires Prowlarr to read parts of the file which may cause high disk or network activity during scans.",
"EnableRss": "Enable RSS",
"EnableRssHelpText": "Enable Rss feed for Indexer",
"EnableSSL": "Enable SSL",
@@ -152,7 +135,6 @@
"Events": "Events",
"EventType": "Event Type",
"Exception": "Exception",
"ExistingMovies": "Existing Movie(s)",
"ExistingTag": "Existing tag",
"Failed": "Failed",
"FeatureRequests": "Feature Requests",
@@ -160,6 +142,7 @@
"Files": "Files",
"Filter": "Filter",
"FilterPlaceHolder": "Search indexers",
"Filters": "Filters",
"Fixed": "Fixed",
"FocusSearchBox": "Focus Search Box",
"Folder": "Folder",
@@ -175,18 +158,21 @@
"HiddenClickToShow": "Hidden, click to show",
"HideAdvanced": "Hide Advanced",
"History": "History",
"HistoryCleanup": "History Cleanup",
"HistoryCleanupDaysHelpText": "Set to 0 to disable automatic cleanup",
"HistoryCleanupDaysHelpTextWarning": "History items older than the selected number of days will be cleaned up automatically",
"HomePage": "Home Page",
"Host": "Host",
"Hostname": "Hostname",
"Id": "Id",
"IgnoredAddresses": "Ignored Addresses",
"IllRestartLater": "I'll restart later",
"Importing": "Importing",
"IncludeHealthWarningsHelpText": "Include Health Warnings",
"Indexer": "Indexer",
"IndexerAuth": "Indexer Auth",
"IndexerFlags": "Indexer Flags",
"IndexerHealthCheckNoIndexers": "No indexers enabled, Prowlarr will not return search results",
"IndexerInfo": "Indexer Info",
"IndexerLongTermStatusCheckAllClientMessage": "All indexers are unavailable due to failures for more than 6 hours",
"IndexerLongTermStatusCheckSingleClientMessage": "Indexers unavailable due to failures for more than 6 hours: {0}",
"IndexerObsoleteCheckMessage": "Indexers are obsolete or have been updated: {0}. Please remove and (or) re-add to Prowlarr",
@@ -203,7 +189,7 @@
"IndexersSelectedInterp": "{0} Indexer(s) Selected",
"IndexerStatusCheckAllClientMessage": "All indexers are unavailable due to failures",
"IndexerStatusCheckSingleClientMessage": "Indexers unavailable due to failures: {0}",
"IndexerTagsHelpText": "Use tags to specify default clients, specify Indexer Proxies, or just to organize your indexers.",
"IndexerTagsHelpText": "Use tags to specify Indexer Proxies or just to organize your indexers.",
"IndexerVipCheckExpiredClientMessage": "Indexer VIP benefits have expired: {0}",
"IndexerVipCheckExpiringClientMessage": "Indexer VIP benefits expiring soon: {0}",
"Info": "Info",
@@ -211,7 +197,6 @@
"Interval": "Interval",
"KeyboardShortcuts": "Keyboard Shortcuts",
"Language": "Language",
"Languages": "Languages",
"LastWriteTime": "Last Write Time",
"LaunchBrowserHelpText": " Open a web browser and navigate to the Prowlarr homepage on app start.",
"Level": "Level",
@@ -220,27 +205,16 @@
"LogLevel": "Log Level",
"LogLevelTraceHelpTextWarning": "Trace logging should only be enabled temporarily",
"Logs": "Logs",
"MaintenanceRelease": "Maintenance release",
"MaintenanceRelease": "Maintenance Release: bug fixes and other improvements. See Github Commit History for more details",
"Manual": "Manual",
"MaximumLimits": "Maximum Limits",
"MassEditor": "Mass Editor",
"Mechanism": "Mechanism",
"Message": "Message",
"MIA": "MIA",
"MinimumLimits": "Minimum Limits",
"MinutesHundredTwenty": "120 Minutes: {0}",
"MinutesNinety": "90 Minutes: {0}",
"MinutesSixty": "60 Minutes: {0}",
"Mode": "Mode",
"MonoNotNetCoreCheckMessage": "Please upgrade to the .NET Core version of Prowlarr",
"MonoTlsCheckMessage": "Prowlarr Mono 4.x tls workaround still enabled, consider removing MONO_TLS_PROVIDER=legacy environment option",
"MonoVersion": "Mono Version",
"MonoVersionCheckUpgradeRecommendedMessage": "Currently installed Mono version {0} is supported but upgrading to {1} is recommended.",
"MoreInfo": "More Info",
"MovieDetailsNextMovie": "Movie Details: Next Movie",
"MovieDetailsPreviousMovie": "Movie Details: Previous Movie",
"MovieIndexScrollBottom": "Movie Index: Scroll Bottom",
"MovieIndexScrollTop": "Movie Index: Scroll Top",
"Movies": "Movies",
"MovieSearch": "Movie Search",
"Name": "Name",
"NetCore": ".NET",
@@ -249,10 +223,8 @@
"NoChange": "No Change",
"NoChanges": "No Changes",
"NoLeaveIt": "No, Leave It",
"NoLimitForAnyRuntime": "No limit for any runtime",
"NoLinks": "No Links",
"NoLogFiles": "No log files",
"NoMinimumForAnyRuntime": "No minimum for any runtime",
"NoSearchResultsFound": "No search results found, try performing a new search below.",
"NoTagsHaveBeenAddedYet": "No tags have been added yet",
"Notification": "Notification",
@@ -262,6 +234,10 @@
"NoUpdatesAreAvailable": "No updates are available",
"OAuthPopupMessage": "Pop-ups are being blocked by your browser",
"Ok": "Ok",
"OnApplicationUpdate": "On Application Update",
"OnApplicationUpdateHelpText": "On Application Update",
"OnGrab": "On Grab",
"OnHealthIssue": "On Health Issue",
"OnHealthIssueHelpText": "On Health Issue",
"OpenBrowserOnStart": "Open browser on start",
"OpenThisModal": "Open This Modal",
@@ -271,21 +247,21 @@
"PageSizeHelpText": "Number of items to show on each page",
"Password": "Password",
"Peers": "Peers",
"Pending": "Pending",
"PendingChangesDiscardChanges": "Discard changes and leave",
"PendingChangesMessage": "You have unsaved changes, are you sure you want to leave this page?",
"PendingChangesStayReview": "Stay and review changes",
"Port": "Port",
"PortNumber": "Port Number",
"PreferredSize": "Preferred Size",
"Presets": "Presets",
"Priority": "Priority",
"PriorityHelpText": "Prioritize multiple Download Clients. Round-Robin is used for clients with the same priority.",
"PrioritySettings": "Priority",
"Privacy": "Privacy",
"Private": "Private",
"Protocol": "Protocol",
"ProwlarrSupportsAnyDownloadClient": "Prowlarr supports any of the download clients listed below.",
"ProwlarrSupportsAnyIndexer": "Prowlarr supports many indexers in addition to any indexer that uses the Newznab/Torznab standard using 'Generic Newznab' (for usenet) or 'Generic Torznab' (for torrents). Search & Select your indexer from below.",
"Proxies": "Proxies",
"Proxy": "Proxy",
"ProxyBypassFilterHelpText": "Use ',' as a separator, and '*.' as a wildcard for subdomains",
"ProxyCheckBadRequestMessage": "Failed to test proxy. StatusCode: {0}",
@@ -295,10 +271,10 @@
"ProxyType": "Proxy Type",
"ProxyUsernameHelpText": "You only need to enter a username and password if one is required. Leave them blank otherwise.",
"PtpOldSettingsCheckMessage": "The following PassThePopcorn indexers have deprecated settings and should be updated: {0}",
"QualityDefinitions": "Quality Definitions",
"QualitySettings": "Quality Settings",
"Public": "Public",
"Query": "Query",
"QueryOptions": "Query Options",
"QueryResults": "Query Results",
"Queue": "Queue",
"ReadTheWikiForMoreInformation": "Read the Wiki for more information",
"Reddit": "Reddit",
@@ -307,7 +283,6 @@
"Refresh": "Refresh",
"RefreshMovie": "Refresh movie",
"ReleaseBranchCheckOfficialBranchMessage": "Branch {0} is not a valid Prowlarr release branch, you will not receive updates",
"ReleaseBranchCheckPreviousVersionMessage": "Branch {0} is for a previous version of Prowlarr, set branch to 'Nightly' for further updates",
"ReleaseStatus": "Release Status",
"Reload": "Reload",
"RemovedFromTaskQueue": "Removed from task queue",
@@ -321,7 +296,6 @@
"RestartRequiredHelpTextWarning": "Requires restart to take effect",
"Restore": "Restore",
"RestoreBackup": "Restore Backup",
"Restrictions": "Restrictions",
"Result": "Result",
"Retention": "Retention",
"RSS": "RSS",
@@ -337,6 +311,7 @@
"Security": "Security",
"Seeders": "Seeders",
"SelectAll": "Select All",
"SemiPrivate": "Semi-Private",
"SendAnonymousUsageData": "Send Anonymous Usage Data",
"SetTags": "Set Tags",
"Settings": "Settings",
@@ -393,6 +368,7 @@
"TestAll": "Test All",
"TestAllApps": "Test All Apps",
"TestAllClients": "Test All Clients",
"TestAllIndexers": "Test All Indexers",
"Time": "Time",
"Title": "Title",
"Today": "Today",
@@ -413,6 +389,7 @@
"UnableToAddANewIndexerPleaseTryAgain": "Unable to add a new indexer, please try again.",
"UnableToAddANewIndexerProxyPleaseTryAgain": "Unable to add a new indexer proxy, please try again.",
"UnableToAddANewNotificationPleaseTryAgain": "Unable to add a new notification, please try again.",
"UnableToLoadApplicationList": "Unable to load application list",
"UnableToLoadAppProfiles": "Unable to load app profiles",
"UnableToLoadBackups": "Unable to load backups",
"UnableToLoadDevelopmentSettings": "Unable to load Development settings",
@@ -420,9 +397,7 @@
"UnableToLoadGeneralSettings": "Unable to load General settings",
"UnableToLoadHistory": "Unable to load history",
"UnableToLoadIndexerProxies": "Unable To Load Indexer Proxies",
"UnableToLoadIndexers": "Unable to load Indexers",
"UnableToLoadNotifications": "Unable to load Notifications",
"UnableToLoadQualityDefinitions": "Unable to load Quality Definitions",
"UnableToLoadTags": "Unable to load Tags",
"UnableToLoadUISettings": "Unable to load UI settings",
"UnsavedChanges": "Unsaved Changes",
@@ -435,15 +410,18 @@
"Updates": "Updates",
"UpdateScriptPathHelpText": "Path to a custom script that takes an extracted update package and handle the remainder of the update process",
"Uptime": "Uptime",
"Url": "Url",
"URLBase": "URL Base",
"UrlBaseHelpText": "For reverse proxy support, default is empty",
"Usenet": "Usenet",
"UseProxy": "Use Proxy",
"UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent provided by the app that called the API",
"Username": "Username",
"Version": "Version",
"View": "View",
"Warn": "Warn",
"Website": "Website",
"Wiki": "Wiki",
"YesCancel": "Yes, Cancel",
"Yesterday": "Yesterday"
}
}

View File

@@ -0,0 +1,16 @@
using System;
namespace NzbDrone.Core.Notifications
{
public class ApplicationUpdateMessage
{
public string Message { get; set; }
public Version PreviousVersion { get; set; }
public Version NewVersion { get; set; }
public override string ToString()
{
return NewVersion.ToString();
}
}
}

View File

@@ -20,6 +20,11 @@ namespace NzbDrone.Core.Notifications.Boxcar
_proxy.SendNotification(HEALTH_ISSUE_TITLE, message.Message, Settings);
}
public override void OnApplicationUpdate(ApplicationUpdateMessage message)
{
_proxy.SendNotification(APPLICATION_UPDATE_TITLE, message.Message, Settings);
}
public override ValidationResult Test()
{
var failures = new List<ValidationFailure>();

View File

@@ -44,6 +44,18 @@ namespace NzbDrone.Core.Notifications.CustomScript
ExecuteScript(environmentVariables);
}
public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage)
{
var environmentVariables = new StringDictionary();
environmentVariables.Add("Prowlarr_EventType", "ApplicationUpdate");
environmentVariables.Add("Prowlarr_Update_Message", updateMessage.Message);
environmentVariables.Add("Prowlarr_Update_NewVersion", updateMessage.NewVersion.ToString());
environmentVariables.Add("Prowlarr_Update_PreviousVersion", updateMessage.PreviousVersion.ToString());
ExecuteScript(environmentVariables);
}
public override ValidationResult Test()
{
var failures = new List<ValidationFailure>();

View File

@@ -42,6 +42,41 @@ namespace NzbDrone.Core.Notifications.Discord
_proxy.SendPayload(payload, Settings);
}
public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage)
{
var attachments = new List<Embed>
{
new Embed
{
Author = new DiscordAuthor
{
Name = Settings.Author.IsNullOrWhiteSpace() ? Environment.MachineName : Settings.Author,
IconUrl = "https://raw.githubusercontent.com/Prowlarr/Prowlarr/develop/Logo/256.png"
},
Title = APPLICATION_UPDATE_TITLE,
Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),
Color = (int)DiscordColors.Standard,
Fields = new List<DiscordField>()
{
new DiscordField()
{
Name = "Previous Version",
Value = updateMessage.PreviousVersion.ToString()
},
new DiscordField()
{
Name = "New Version",
Value = updateMessage.NewVersion.ToString()
}
},
}
};
var payload = CreatePayload(null, attachments);
_proxy.SendPayload(payload, Settings);
}
public override ValidationResult Test()
{
var failures = new List<ValidationFailure>();

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