@@ -219,6 +235,8 @@ class InteractiveImportRow extends Component {
/>
) : pathCellContents;
+ const isIndexerFlagsColumnVisible = columns.find((c) => c.name === 'indexerFlags')?.isVisible ?? false;
+
return (
+ {isIndexerFlagsColumnVisible ? (
+
+ {showIndexerFlagsPlaceholder ? (
+
+ ) : (
+ <>
+ {indexerFlags ? (
+ }
+ title={translate('IndexerFlags')}
+ body={}
+ position={tooltipPositions.LEFT}
+ />
+ ) : null}
+ >
+ )}
+
+ ) : null}
+
{
rejections.length ?
@@ -395,6 +435,13 @@ class InteractiveImportRow extends Component {
real={quality ? quality.revision.real > 0 : false}
onModalClose={this.onSelectQualityModalClose}
/>
+
+
);
}
@@ -413,7 +460,9 @@ InteractiveImportRow.propTypes = {
quality: PropTypes.object,
size: PropTypes.number.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object),
+ indexerFlags: PropTypes.number.isRequired,
rejections: PropTypes.arrayOf(PropTypes.object).isRequired,
+ columns: PropTypes.arrayOf(PropTypes.object).isRequired,
audioTags: PropTypes.object.isRequired,
additionalFile: PropTypes.bool.isRequired,
isReprocessing: PropTypes.bool,
diff --git a/frontend/src/InteractiveSearch/InteractiveSearch.js b/frontend/src/InteractiveSearch/InteractiveSearch.js
index 6e74695b0..64d1ce730 100644
--- a/frontend/src/InteractiveSearch/InteractiveSearch.js
+++ b/frontend/src/InteractiveSearch/InteractiveSearch.js
@@ -65,6 +65,15 @@ const columns = [
isSortable: true,
isVisible: true
},
+ {
+ name: 'indexerFlags',
+ label: React.createElement(Icon, {
+ name: icons.FLAG,
+ title: () => translate('IndexerFlags')
+ }),
+ isSortable: true,
+ isVisible: true
+ },
{
name: 'rejections',
label: React.createElement(Icon, {
diff --git a/frontend/src/InteractiveSearch/InteractiveSearchRow.css b/frontend/src/InteractiveSearch/InteractiveSearchRow.css
index ffea82600..dad7242c8 100644
--- a/frontend/src/InteractiveSearch/InteractiveSearchRow.css
+++ b/frontend/src/InteractiveSearch/InteractiveSearchRow.css
@@ -35,6 +35,7 @@
}
.rejected,
+.indexerFlags,
.download {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
diff --git a/frontend/src/InteractiveSearch/InteractiveSearchRow.css.d.ts b/frontend/src/InteractiveSearch/InteractiveSearchRow.css.d.ts
index ca01c5ee6..bec6dcf78 100644
--- a/frontend/src/InteractiveSearch/InteractiveSearchRow.css.d.ts
+++ b/frontend/src/InteractiveSearch/InteractiveSearchRow.css.d.ts
@@ -5,6 +5,7 @@ interface CssExports {
'customFormatScore': string;
'download': string;
'indexer': string;
+ 'indexerFlags': string;
'peers': string;
'protocol': string;
'quality': string;
diff --git a/frontend/src/InteractiveSearch/InteractiveSearchRow.js b/frontend/src/InteractiveSearch/InteractiveSearchRow.js
index db65ae575..a139f8085 100644
--- a/frontend/src/InteractiveSearch/InteractiveSearchRow.js
+++ b/frontend/src/InteractiveSearch/InteractiveSearchRow.js
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import ProtocolLabel from 'Activity/Queue/ProtocolLabel';
import AlbumFormats from 'Album/AlbumFormats';
+import IndexerFlags from 'Album/IndexerFlags';
import TrackQuality from 'Album/TrackQuality';
import Icon from 'Components/Icon';
import Link from 'Components/Link/Link';
@@ -129,6 +130,7 @@ class InteractiveSearchRow extends Component {
quality,
customFormatScore,
customFormats,
+ indexerFlags = 0,
rejections,
downloadAllowed,
isGrabbing,
@@ -187,10 +189,21 @@ class InteractiveSearchRow extends Component {
formatCustomFormatScore(customFormatScore, customFormats.length)
}
tooltip={
}
- position={tooltipPositions.BOTTOM}
+ position={tooltipPositions.LEFT}
/>
+
+ {indexerFlags ? (
+ }
+ title={translate('IndexerFlags')}
+ body={}
+ position={tooltipPositions.LEFT}
+ />
+ ) : null}
+
+
{
!!rejections.length &&
@@ -265,6 +278,7 @@ InteractiveSearchRow.propTypes = {
quality: PropTypes.object.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object),
customFormatScore: PropTypes.number.isRequired,
+ indexerFlags: PropTypes.number.isRequired,
rejections: PropTypes.arrayOf(PropTypes.string).isRequired,
downloadAllowed: PropTypes.bool.isRequired,
isGrabbing: PropTypes.bool.isRequired,
@@ -277,6 +291,7 @@ InteractiveSearchRow.propTypes = {
};
InteractiveSearchRow.defaultProps = {
+ indexerFlags: 0,
rejections: [],
isGrabbing: false,
isGrabbed: false
diff --git a/frontend/src/Store/Actions/Settings/indexerFlags.js b/frontend/src/Store/Actions/Settings/indexerFlags.js
new file mode 100644
index 000000000..a53fe1c61
--- /dev/null
+++ b/frontend/src/Store/Actions/Settings/indexerFlags.js
@@ -0,0 +1,48 @@
+import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
+import { createThunk } from 'Store/thunks';
+
+//
+// Variables
+
+const section = 'settings.indexerFlags';
+
+//
+// Actions Types
+
+export const FETCH_INDEXER_FLAGS = 'settings/indexerFlags/fetchIndexerFlags';
+
+//
+// Action Creators
+
+export const fetchIndexerFlags = createThunk(FETCH_INDEXER_FLAGS);
+
+//
+// Details
+
+export default {
+
+ //
+ // State
+
+ defaultState: {
+ isFetching: false,
+ isPopulated: false,
+ error: null,
+ items: []
+ },
+
+ //
+ // Action Handlers
+
+ actionHandlers: {
+ [FETCH_INDEXER_FLAGS]: createFetchHandler(section, '/indexerFlag')
+ },
+
+ //
+ // Reducers
+
+ reducers: {
+
+ }
+
+};
diff --git a/frontend/src/Store/Actions/interactiveImportActions.js b/frontend/src/Store/Actions/interactiveImportActions.js
index e0e295568..d174f443b 100644
--- a/frontend/src/Store/Actions/interactiveImportActions.js
+++ b/frontend/src/Store/Actions/interactiveImportActions.js
@@ -208,6 +208,7 @@ export const actionHandlers = handleThunks({
trackIds: (item.tracks || []).map((e) => e.id),
quality: item.quality,
releaseGroup: item.releaseGroup,
+ indexerFlags: item.indexerFlags,
downloadId: item.downloadId,
additionalFile: item.additionalFile,
replaceExistingFiles: item.replaceExistingFiles,
diff --git a/frontend/src/Store/Actions/settingsActions.js b/frontend/src/Store/Actions/settingsActions.js
index b787110c1..54b059083 100644
--- a/frontend/src/Store/Actions/settingsActions.js
+++ b/frontend/src/Store/Actions/settingsActions.js
@@ -11,6 +11,7 @@ import downloadClients from './Settings/downloadClients';
import general from './Settings/general';
import importListExclusions from './Settings/importListExclusions';
import importLists from './Settings/importLists';
+import indexerFlags from './Settings/indexerFlags';
import indexerOptions from './Settings/indexerOptions';
import indexers from './Settings/indexers';
import languages from './Settings/languages';
@@ -38,6 +39,7 @@ export * from './Settings/downloadClientOptions';
export * from './Settings/general';
export * from './Settings/importLists';
export * from './Settings/importListExclusions';
+export * from './Settings/indexerFlags';
export * from './Settings/indexerOptions';
export * from './Settings/indexers';
export * from './Settings/languages';
@@ -73,6 +75,7 @@ export const defaultState = {
downloadClients: downloadClients.defaultState,
downloadClientOptions: downloadClientOptions.defaultState,
general: general.defaultState,
+ indexerFlags: indexerFlags.defaultState,
indexerOptions: indexerOptions.defaultState,
indexers: indexers.defaultState,
importLists: importLists.defaultState,
@@ -119,6 +122,7 @@ export const actionHandlers = handleThunks({
...downloadClients.actionHandlers,
...downloadClientOptions.actionHandlers,
...general.actionHandlers,
+ ...indexerFlags.actionHandlers,
...indexerOptions.actionHandlers,
...indexers.actionHandlers,
...importLists.actionHandlers,
@@ -156,6 +160,7 @@ export const reducers = createHandleActions({
...downloadClients.reducers,
...downloadClientOptions.reducers,
...general.reducers,
+ ...indexerFlags.reducers,
...indexerOptions.reducers,
...indexers.reducers,
...importLists.reducers,
diff --git a/frontend/src/Store/Actions/trackActions.js b/frontend/src/Store/Actions/trackActions.js
index bd1f472c3..a71388c88 100644
--- a/frontend/src/Store/Actions/trackActions.js
+++ b/frontend/src/Store/Actions/trackActions.js
@@ -77,6 +77,15 @@ export const defaultState = {
}),
isVisible: false
},
+ {
+ name: 'indexerFlags',
+ columnLabel: () => translate('IndexerFlags'),
+ label: React.createElement(Icon, {
+ name: icons.FLAG,
+ title: () => translate('IndexerFlags')
+ }),
+ isVisible: false
+ },
{
name: 'status',
label: () => translate('Status'),
diff --git a/frontend/src/Store/Selectors/createIndexerFlagsSelector.ts b/frontend/src/Store/Selectors/createIndexerFlagsSelector.ts
new file mode 100644
index 000000000..90587639c
--- /dev/null
+++ b/frontend/src/Store/Selectors/createIndexerFlagsSelector.ts
@@ -0,0 +1,9 @@
+import { createSelector } from 'reselect';
+import AppState from 'App/State/AppState';
+
+const createIndexerFlagsSelector = createSelector(
+ (state: AppState) => state.settings.indexerFlags,
+ (indexerFlags) => indexerFlags
+);
+
+export default createIndexerFlagsSelector;
diff --git a/frontend/src/TrackFile/TrackFile.ts b/frontend/src/TrackFile/TrackFile.ts
index ce9379816..ef4dc65f3 100644
--- a/frontend/src/TrackFile/TrackFile.ts
+++ b/frontend/src/TrackFile/TrackFile.ts
@@ -13,6 +13,7 @@ export interface TrackFile extends ModelBase {
releaseGroup: string;
quality: QualityModel;
customFormats: CustomFormat[];
+ indexerFlags: number;
mediaInfo: MediaInfo;
qualityCutoffNotMet: boolean;
}
diff --git a/frontend/src/typings/IndexerFlag.ts b/frontend/src/typings/IndexerFlag.ts
new file mode 100644
index 000000000..2c7d97a73
--- /dev/null
+++ b/frontend/src/typings/IndexerFlag.ts
@@ -0,0 +1,6 @@
+interface IndexerFlag {
+ id: number;
+ name: string;
+}
+
+export default IndexerFlag;
diff --git a/src/Lidarr.Api.V1/Indexers/IndexerFlagController.cs b/src/Lidarr.Api.V1/Indexers/IndexerFlagController.cs
new file mode 100644
index 000000000..f41700d83
--- /dev/null
+++ b/src/Lidarr.Api.V1/Indexers/IndexerFlagController.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Lidarr.Http;
+using Microsoft.AspNetCore.Mvc;
+using NzbDrone.Core.Parser.Model;
+
+namespace Lidarr.Api.V1.Indexers
+{
+ [V1ApiController]
+ public class IndexerFlagController : Controller
+ {
+ [HttpGet]
+ public List GetAll()
+ {
+ return Enum.GetValues(typeof(IndexerFlags)).Cast().Select(f => new IndexerFlagResource
+ {
+ Id = (int)f,
+ Name = f.ToString()
+ }).ToList();
+ }
+ }
+}
diff --git a/src/Lidarr.Api.V1/Indexers/IndexerFlagResource.cs b/src/Lidarr.Api.V1/Indexers/IndexerFlagResource.cs
new file mode 100644
index 000000000..385f0a50c
--- /dev/null
+++ b/src/Lidarr.Api.V1/Indexers/IndexerFlagResource.cs
@@ -0,0 +1,13 @@
+using Lidarr.Http.REST;
+using Newtonsoft.Json;
+
+namespace Lidarr.Api.V1.Indexers
+{
+ public class IndexerFlagResource : RestResource
+ {
+ [JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)]
+ public new int Id { get; set; }
+ public string Name { get; set; }
+ public string NameLower => Name.ToLowerInvariant();
+ }
+}
diff --git a/src/Lidarr.Api.V1/Indexers/ReleaseResource.cs b/src/Lidarr.Api.V1/Indexers/ReleaseResource.cs
index 5ad2b70d0..e8fc6f891 100644
--- a/src/Lidarr.Api.V1/Indexers/ReleaseResource.cs
+++ b/src/Lidarr.Api.V1/Indexers/ReleaseResource.cs
@@ -49,6 +49,7 @@ namespace Lidarr.Api.V1.Indexers
public int? Seeders { get; set; }
public int? Leechers { get; set; }
public DownloadProtocol Protocol { get; set; }
+ public int IndexerFlags { get; set; }
// Sent when queuing an unknown release
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
@@ -76,6 +77,7 @@ namespace Lidarr.Api.V1.Indexers
var parsedAlbumInfo = model.RemoteAlbum.ParsedAlbumInfo;
var remoteAlbum = model.RemoteAlbum;
var torrentInfo = (model.RemoteAlbum.Release as TorrentInfo) ?? new TorrentInfo();
+ var indexerFlags = torrentInfo.IndexerFlags;
// TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead? (Got a huge Deja Vu, didn't we talk about this already once?)
return new ReleaseResource
@@ -115,6 +117,7 @@ namespace Lidarr.Api.V1.Indexers
Seeders = torrentInfo.Seeders,
Leechers = (torrentInfo.Peers.HasValue && torrentInfo.Seeders.HasValue) ? (torrentInfo.Peers.Value - torrentInfo.Seeders.Value) : (int?)null,
Protocol = releaseInfo.DownloadProtocol,
+ IndexerFlags = (int)indexerFlags,
};
}
diff --git a/src/Lidarr.Api.V1/ManualImport/ManualImportController.cs b/src/Lidarr.Api.V1/ManualImport/ManualImportController.cs
index b11c36a91..fa4c95187 100644
--- a/src/Lidarr.Api.V1/ManualImport/ManualImportController.cs
+++ b/src/Lidarr.Api.V1/ManualImport/ManualImportController.cs
@@ -80,6 +80,7 @@ namespace Lidarr.Api.V1.ManualImport
Release = resource.AlbumReleaseId.HasValue ? _releaseService.GetRelease(resource.AlbumReleaseId.Value) : null,
Quality = resource.Quality,
ReleaseGroup = resource.ReleaseGroup,
+ IndexerFlags = resource.IndexerFlags,
DownloadId = resource.DownloadId,
AdditionalFile = resource.AdditionalFile,
ReplaceExistingFiles = resource.ReplaceExistingFiles,
diff --git a/src/Lidarr.Api.V1/ManualImport/ManualImportResource.cs b/src/Lidarr.Api.V1/ManualImport/ManualImportResource.cs
index 4b38b4f7c..b2f70eb3f 100644
--- a/src/Lidarr.Api.V1/ManualImport/ManualImportResource.cs
+++ b/src/Lidarr.Api.V1/ManualImport/ManualImportResource.cs
@@ -24,6 +24,7 @@ namespace Lidarr.Api.V1.ManualImport
public string ReleaseGroup { get; set; }
public int QualityWeight { get; set; }
public string DownloadId { get; set; }
+ public int IndexerFlags { get; set; }
public IEnumerable Rejections { get; set; }
public ParsedTrackInfo AudioTags { get; set; }
public bool AdditionalFile { get; set; }
@@ -55,7 +56,9 @@ namespace Lidarr.Api.V1.ManualImport
// QualityWeight
DownloadId = model.DownloadId,
+ IndexerFlags = model.IndexerFlags,
Rejections = model.Rejections,
+
AudioTags = model.Tags,
AdditionalFile = model.AdditionalFile,
ReplaceExistingFiles = model.ReplaceExistingFiles,
diff --git a/src/Lidarr.Api.V1/ManualImport/ManualImportUpdateResource.cs b/src/Lidarr.Api.V1/ManualImport/ManualImportUpdateResource.cs
index 84a513807..3a4bbc6f4 100644
--- a/src/Lidarr.Api.V1/ManualImport/ManualImportUpdateResource.cs
+++ b/src/Lidarr.Api.V1/ManualImport/ManualImportUpdateResource.cs
@@ -17,6 +17,7 @@ namespace Lidarr.Api.V1.ManualImport
public List TrackIds { get; set; }
public QualityModel Quality { get; set; }
public string ReleaseGroup { get; set; }
+ public int IndexerFlags { get; set; }
public string DownloadId { get; set; }
public bool AdditionalFile { get; set; }
public bool ReplaceExistingFiles { get; set; }
diff --git a/src/Lidarr.Api.V1/TrackFiles/TrackFileResource.cs b/src/Lidarr.Api.V1/TrackFiles/TrackFileResource.cs
index 5c6695875..d09fbff97 100644
--- a/src/Lidarr.Api.V1/TrackFiles/TrackFileResource.cs
+++ b/src/Lidarr.Api.V1/TrackFiles/TrackFileResource.cs
@@ -24,6 +24,7 @@ namespace Lidarr.Api.V1.TrackFiles
public int QualityWeight { get; set; }
public List CustomFormats { get; set; }
public int CustomFormatScore { get; set; }
+ public int? IndexerFlags { get; set; }
public MediaInfoResource MediaInfo { get; set; }
public bool QualityCutoffNotMet { get; set; }
@@ -94,7 +95,8 @@ namespace Lidarr.Api.V1.TrackFiles
MediaInfo = model.MediaInfo.ToResource(),
QualityCutoffNotMet = upgradableSpecification.QualityCutoffNotMet(artist.QualityProfile.Value, model.Quality),
CustomFormats = customFormats.ToResource(false),
- CustomFormatScore = customFormatScore
+ CustomFormatScore = customFormatScore,
+ IndexerFlags = (int)model.IndexerFlags
};
}
}
diff --git a/src/NzbDrone.Core.Test/MediaFiles/TrackImport/ImportDecisionMakerFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/TrackImport/ImportDecisionMakerFixture.cs
index a2ece8263..826d7c129 100644
--- a/src/NzbDrone.Core.Test/MediaFiles/TrackImport/ImportDecisionMakerFixture.cs
+++ b/src/NzbDrone.Core.Test/MediaFiles/TrackImport/ImportDecisionMakerFixture.cs
@@ -8,6 +8,7 @@ using Moq;
using NUnit.Framework;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
+using NzbDrone.Core.History;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.TrackImport;
using NzbDrone.Core.MediaFiles.TrackImport.Aggregation;
@@ -130,6 +131,10 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
.Setup(c => c.FilterUnchangedFiles(It.IsAny>(), It.IsAny()))
.Returns((List files, FilterFilesType filter) => files);
+ Mocker.GetMock()
+ .Setup(x => x.FindByDownloadId(It.IsAny()))
+ .Returns(new List());
+
GivenSpecifications(_albumpass1);
}
diff --git a/src/NzbDrone.Core/Blocklisting/Blocklist.cs b/src/NzbDrone.Core/Blocklisting/Blocklist.cs
index c01077a9e..17c092924 100644
--- a/src/NzbDrone.Core/Blocklisting/Blocklist.cs
+++ b/src/NzbDrone.Core/Blocklisting/Blocklist.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Music;
+using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
namespace NzbDrone.Core.Blocklisting
@@ -19,6 +20,7 @@ namespace NzbDrone.Core.Blocklisting
public long? Size { get; set; }
public DownloadProtocol Protocol { get; set; }
public string Indexer { get; set; }
+ public IndexerFlags IndexerFlags { get; set; }
public string Message { get; set; }
public string TorrentInfoHash { get; set; }
}
diff --git a/src/NzbDrone.Core/Blocklisting/BlocklistService.cs b/src/NzbDrone.Core/Blocklisting/BlocklistService.cs
index 6734a3318..18c4503f1 100644
--- a/src/NzbDrone.Core/Blocklisting/BlocklistService.cs
+++ b/src/NzbDrone.Core/Blocklisting/BlocklistService.cs
@@ -188,6 +188,11 @@ namespace NzbDrone.Core.Blocklisting
TorrentInfoHash = message.Data.GetValueOrDefault("torrentInfoHash")
};
+ if (Enum.TryParse(message.Data.GetValueOrDefault("indexerFlags"), true, out IndexerFlags flags))
+ {
+ blocklist.IndexerFlags = flags;
+ }
+
_blocklistRepository.Insert(blocklist);
}
diff --git a/src/NzbDrone.Core/CustomFormats/CustomFormatCalculationService.cs b/src/NzbDrone.Core/CustomFormats/CustomFormatCalculationService.cs
index 33f85050b..0eb14fef0 100644
--- a/src/NzbDrone.Core/CustomFormats/CustomFormatCalculationService.cs
+++ b/src/NzbDrone.Core/CustomFormats/CustomFormatCalculationService.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -38,7 +39,8 @@ namespace NzbDrone.Core.CustomFormats
{
AlbumInfo = remoteAlbum.ParsedAlbumInfo,
Artist = remoteAlbum.Artist,
- Size = size
+ Size = size,
+ IndexerFlags = remoteAlbum.Release?.IndexerFlags ?? 0
};
return ParseCustomFormat(input);
@@ -70,7 +72,8 @@ namespace NzbDrone.Core.CustomFormats
{
AlbumInfo = albumInfo,
Artist = artist,
- Size = blocklist.Size ?? 0
+ Size = blocklist.Size ?? 0,
+ IndexerFlags = blocklist.IndexerFlags
};
return ParseCustomFormat(input);
@@ -81,6 +84,7 @@ namespace NzbDrone.Core.CustomFormats
var parsed = Parser.Parser.ParseAlbumTitle(history.SourceTitle);
long.TryParse(history.Data.GetValueOrDefault("size"), out var size);
+ Enum.TryParse(history.Data.GetValueOrDefault("indexerFlags"), true, out IndexerFlags indexerFlags);
var albumInfo = new ParsedAlbumInfo
{
@@ -94,7 +98,8 @@ namespace NzbDrone.Core.CustomFormats
{
AlbumInfo = albumInfo,
Artist = artist,
- Size = size
+ Size = size,
+ IndexerFlags = indexerFlags
};
return ParseCustomFormat(input);
@@ -115,7 +120,8 @@ namespace NzbDrone.Core.CustomFormats
AlbumInfo = albumInfo,
Artist = localTrack.Artist,
Size = localTrack.Size,
- Filename = Path.GetFileName(localTrack.Path)
+ Filename = Path.GetFileName(localTrack.Path),
+ IndexerFlags = localTrack.IndexerFlags,
};
return ParseCustomFormat(input);
@@ -182,6 +188,7 @@ namespace NzbDrone.Core.CustomFormats
AlbumInfo = albumInfo,
Artist = artist,
Size = trackFile.Size,
+ IndexerFlags = trackFile.IndexerFlags,
Filename = Path.GetFileName(trackFile.Path)
};
diff --git a/src/NzbDrone.Core/CustomFormats/CustomFormatInput.cs b/src/NzbDrone.Core/CustomFormats/CustomFormatInput.cs
index 83efff8bb..f43003b47 100644
--- a/src/NzbDrone.Core/CustomFormats/CustomFormatInput.cs
+++ b/src/NzbDrone.Core/CustomFormats/CustomFormatInput.cs
@@ -8,6 +8,7 @@ namespace NzbDrone.Core.CustomFormats
public ParsedAlbumInfo AlbumInfo { get; set; }
public Artist Artist { get; set; }
public long Size { get; set; }
+ public IndexerFlags IndexerFlags { get; set; }
public string Filename { get; set; }
// public CustomFormatInput(ParsedEpisodeInfo episodeInfo, Series series)
diff --git a/src/NzbDrone.Core/CustomFormats/Specifications/IndexerFlagSpecification.cs b/src/NzbDrone.Core/CustomFormats/Specifications/IndexerFlagSpecification.cs
new file mode 100644
index 000000000..3eaeeb5f6
--- /dev/null
+++ b/src/NzbDrone.Core/CustomFormats/Specifications/IndexerFlagSpecification.cs
@@ -0,0 +1,44 @@
+using System;
+using FluentValidation;
+using NzbDrone.Core.Annotations;
+using NzbDrone.Core.Parser.Model;
+using NzbDrone.Core.Validation;
+
+namespace NzbDrone.Core.CustomFormats
+{
+ public class IndexerFlagSpecificationValidator : AbstractValidator
+ {
+ public IndexerFlagSpecificationValidator()
+ {
+ RuleFor(c => c.Value).NotEmpty();
+ RuleFor(c => c.Value).Custom((flag, context) =>
+ {
+ if (!Enum.IsDefined(typeof(IndexerFlags), flag))
+ {
+ context.AddFailure($"Invalid indexer flag condition value: {flag}");
+ }
+ });
+ }
+ }
+
+ public class IndexerFlagSpecification : CustomFormatSpecificationBase
+ {
+ private static readonly IndexerFlagSpecificationValidator Validator = new ();
+
+ public override int Order => 4;
+ public override string ImplementationName => "Indexer Flag";
+
+ [FieldDefinition(1, Label = "CustomFormatsSpecificationFlag", Type = FieldType.Select, SelectOptions = typeof(IndexerFlags))]
+ public int Value { get; set; }
+
+ protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)
+ {
+ return input.IndexerFlags.HasFlag((IndexerFlags)Value);
+ }
+
+ public override NzbDroneValidationResult Validate()
+ {
+ return new NzbDroneValidationResult(Validator.Validate(this));
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/Datastore/Migration/078_add_indexer_flags.cs b/src/NzbDrone.Core/Datastore/Migration/078_add_indexer_flags.cs
new file mode 100644
index 000000000..46ff2d20b
--- /dev/null
+++ b/src/NzbDrone.Core/Datastore/Migration/078_add_indexer_flags.cs
@@ -0,0 +1,15 @@
+using FluentMigrator;
+using NzbDrone.Core.Datastore.Migration.Framework;
+
+namespace NzbDrone.Core.Datastore.Migration
+{
+ [Migration(078)]
+ public class add_indexer_flags : NzbDroneMigrationBase
+ {
+ protected override void MainDbUpgrade()
+ {
+ Alter.Table("Blocklist").AddColumn("IndexerFlags").AsInt32().WithDefaultValue(0);
+ Alter.Table("TrackFiles").AddColumn("IndexerFlags").AsInt32().WithDefaultValue(0);
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs
index eed5d5405..efe1d2fd4 100644
--- a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs
+++ b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs
@@ -12,6 +12,7 @@ using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Music;
using NzbDrone.Core.Music.Events;
using NzbDrone.Core.Parser;
+using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download.TrackedDownloads
{
@@ -144,12 +145,11 @@ namespace NzbDrone.Core.Download.TrackedDownloads
var firstHistoryItem = historyItems.First();
var grabbedEvent = historyItems.FirstOrDefault(v => v.EventType == EntityHistoryEventType.Grabbed);
- trackedDownload.Indexer = grabbedEvent?.Data["indexer"];
+ trackedDownload.Indexer = grabbedEvent?.Data?.GetValueOrDefault("indexer");
trackedDownload.Added = grabbedEvent?.Date;
if (parsedAlbumInfo == null ||
- trackedDownload.RemoteAlbum == null ||
- trackedDownload.RemoteAlbum.Artist == null ||
+ trackedDownload.RemoteAlbum?.Artist == null ||
trackedDownload.RemoteAlbum.Albums.Empty())
{
// Try parsing the original source title and if that fails, try parsing it as a special
@@ -181,6 +181,13 @@ namespace NzbDrone.Core.Download.TrackedDownloads
}
}
}
+
+ if (trackedDownload.RemoteAlbum != null &&
+ Enum.TryParse(grabbedEvent?.Data?.GetValueOrDefault("indexerFlags"), true, out IndexerFlags flags))
+ {
+ trackedDownload.RemoteAlbum.Release ??= new ReleaseInfo();
+ trackedDownload.RemoteAlbum.Release.IndexerFlags = flags;
+ }
}
// Calculate custom formats
diff --git a/src/NzbDrone.Core/History/EntityHistoryService.cs b/src/NzbDrone.Core/History/EntityHistoryService.cs
index d3e33f9b0..d94d0cf9e 100644
--- a/src/NzbDrone.Core/History/EntityHistoryService.cs
+++ b/src/NzbDrone.Core/History/EntityHistoryService.cs
@@ -166,6 +166,7 @@ namespace NzbDrone.Core.History
history.Data.Add("DownloadForced", (!message.Album.DownloadAllowed).ToString());
history.Data.Add("CustomFormatScore", message.Album.CustomFormatScore.ToString());
history.Data.Add("ReleaseSource", message.Album.ReleaseSource.ToString());
+ history.Data.Add("IndexerFlags", message.Album.Release.IndexerFlags.ToString());
if (!message.Album.ParsedAlbumInfo.ReleaseHash.IsNullOrWhiteSpace())
{
@@ -203,6 +204,8 @@ namespace NzbDrone.Core.History
history.Data.Add("StatusMessages", message.TrackedDownload.StatusMessages.ToJson());
history.Data.Add("ReleaseGroup", message.TrackedDownload?.RemoteAlbum?.ParsedAlbumInfo?.ReleaseGroup);
+ history.Data.Add("IndexerFlags", message.TrackedDownload?.RemoteAlbum?.Release?.IndexerFlags.ToString());
+
_historyRepository.Insert(history);
}
}
@@ -241,6 +244,7 @@ namespace NzbDrone.Core.History
history.Data.Add("DownloadClient", message.DownloadClientInfo?.Name);
history.Data.Add("ReleaseGroup", message.TrackInfo.ReleaseGroup);
history.Data.Add("Size", message.TrackInfo.Size.ToString());
+ history.Data.Add("IndexerFlags", message.ImportedTrack.IndexerFlags.ToString());
_historyRepository.Insert(history);
}
@@ -324,6 +328,7 @@ namespace NzbDrone.Core.History
history.Data.Add("Reason", message.Reason.ToString());
history.Data.Add("ReleaseGroup", message.TrackFile.ReleaseGroup);
history.Data.Add("Size", message.TrackFile.Size.ToString());
+ history.Data.Add("IndexerFlags", message.TrackFile.IndexerFlags.ToString());
_historyRepository.Insert(history);
}
@@ -351,6 +356,7 @@ namespace NzbDrone.Core.History
history.Data.Add("Path", path);
history.Data.Add("ReleaseGroup", message.TrackFile.ReleaseGroup);
history.Data.Add("Size", message.TrackFile.Size.ToString());
+ history.Data.Add("IndexerFlags", message.TrackFile.IndexerFlags.ToString());
_historyRepository.Insert(history);
}
diff --git a/src/NzbDrone.Core/Indexers/FileList/FileListParser.cs b/src/NzbDrone.Core/Indexers/FileList/FileListParser.cs
index 6fb1ef477..f29f22354 100644
--- a/src/NzbDrone.Core/Indexers/FileList/FileListParser.cs
+++ b/src/NzbDrone.Core/Indexers/FileList/FileListParser.cs
@@ -38,8 +38,7 @@ namespace NzbDrone.Core.Indexers.FileList
{
var id = result.Id;
- // if (result.FreeLeech)
- torrentInfos.Add(new TorrentInfo()
+ torrentInfos.Add(new TorrentInfo
{
Guid = $"FileList-{id}",
Title = result.Name,
@@ -48,13 +47,31 @@ namespace NzbDrone.Core.Indexers.FileList
InfoUrl = GetInfoUrl(id),
Seeders = result.Seeders,
Peers = result.Leechers + result.Seeders,
- PublishDate = result.UploadDate.ToUniversalTime()
+ PublishDate = result.UploadDate.ToUniversalTime(),
+ IndexerFlags = GetIndexerFlags(result)
});
}
return torrentInfos.ToArray();
}
+ private static IndexerFlags GetIndexerFlags(FileListTorrent item)
+ {
+ IndexerFlags flags = 0;
+
+ if (item.FreeLeech)
+ {
+ flags |= IndexerFlags.Freeleech;
+ }
+
+ if (item.Internal)
+ {
+ flags |= IndexerFlags.Internal;
+ }
+
+ return flags;
+ }
+
private string GetDownloadUrl(string torrentId)
{
var url = new HttpUri(_settings.BaseUrl)
diff --git a/src/NzbDrone.Core/Indexers/FileList/FileListTorrent.cs b/src/NzbDrone.Core/Indexers/FileList/FileListTorrent.cs
index 01ea834ed..a22fc1c9b 100644
--- a/src/NzbDrone.Core/Indexers/FileList/FileListTorrent.cs
+++ b/src/NzbDrone.Core/Indexers/FileList/FileListTorrent.cs
@@ -16,6 +16,7 @@ namespace NzbDrone.Core.Indexers.FileList
public uint Files { get; set; }
[JsonProperty(PropertyName = "imdb")]
public string ImdbId { get; set; }
+ public bool Internal { get; set; }
[JsonProperty(PropertyName = "freeleech")]
public bool FreeLeech { get; set; }
[JsonProperty(PropertyName = "upload_date")]
diff --git a/src/NzbDrone.Core/Indexers/Gazelle/GazelleApi.cs b/src/NzbDrone.Core/Indexers/Gazelle/GazelleApi.cs
index cadd8cf02..23e57df0c 100644
--- a/src/NzbDrone.Core/Indexers/Gazelle/GazelleApi.cs
+++ b/src/NzbDrone.Core/Indexers/Gazelle/GazelleApi.cs
@@ -34,6 +34,7 @@ namespace NzbDrone.Core.Indexers.Gazelle
public string Leechers { get; set; }
public bool IsFreeLeech { get; set; }
public bool IsNeutralLeech { get; set; }
+ public bool IsFreeload { get; set; }
public bool IsPersonalFreeLeech { get; set; }
public bool CanUseToken { get; set; }
}
diff --git a/src/NzbDrone.Core/Indexers/Gazelle/GazelleParser.cs b/src/NzbDrone.Core/Indexers/Gazelle/GazelleParser.cs
index 7952dc92a..616b48872 100644
--- a/src/NzbDrone.Core/Indexers/Gazelle/GazelleParser.cs
+++ b/src/NzbDrone.Core/Indexers/Gazelle/GazelleParser.cs
@@ -63,7 +63,7 @@ namespace NzbDrone.Core.Indexers.Gazelle
title += " [Cue]";
}
- torrentInfos.Add(new GazelleInfo()
+ torrentInfos.Add(new GazelleInfo
{
Guid = string.Format("Gazelle-{0}", id),
Artist = artist,
@@ -79,7 +79,7 @@ namespace NzbDrone.Core.Indexers.Gazelle
Seeders = int.Parse(torrent.Seeders),
Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders),
PublishDate = torrent.Time.ToUniversalTime(),
- Scene = torrent.Scene,
+ IndexerFlags = GetIndexerFlags(torrent)
});
}
}
@@ -92,6 +92,23 @@ namespace NzbDrone.Core.Indexers.Gazelle
.ToArray();
}
+ private static IndexerFlags GetIndexerFlags(GazelleTorrent torrent)
+ {
+ IndexerFlags flags = 0;
+
+ if (torrent.IsFreeLeech || torrent.IsNeutralLeech || torrent.IsFreeload || torrent.IsPersonalFreeLeech)
+ {
+ flags |= IndexerFlags.Freeleech;
+ }
+
+ if (torrent.Scene)
+ {
+ flags |= IndexerFlags.Scene;
+ }
+
+ return flags;
+ }
+
private string GetDownloadUrl(int torrentId)
{
var url = new HttpUri(_settings.BaseUrl)
diff --git a/src/NzbDrone.Core/Indexers/Redacted/RedactedParser.cs b/src/NzbDrone.Core/Indexers/Redacted/RedactedParser.cs
index bb536e07c..871cbe20c 100644
--- a/src/NzbDrone.Core/Indexers/Redacted/RedactedParser.cs
+++ b/src/NzbDrone.Core/Indexers/Redacted/RedactedParser.cs
@@ -65,7 +65,7 @@ namespace NzbDrone.Core.Indexers.Redacted
Seeders = int.Parse(torrent.Seeders),
Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders),
PublishDate = torrent.Time.ToUniversalTime(),
- Scene = torrent.Scene
+ IndexerFlags = GetIndexerFlags(torrent)
});
}
}
@@ -111,6 +111,23 @@ namespace NzbDrone.Core.Indexers.Redacted
return $"{title} [{string.Join(" / ", flags)}]";
}
+ private static IndexerFlags GetIndexerFlags(GazelleTorrent torrent)
+ {
+ IndexerFlags flags = 0;
+
+ if (torrent.IsFreeLeech || torrent.IsNeutralLeech || torrent.IsFreeload || torrent.IsPersonalFreeLeech)
+ {
+ flags |= IndexerFlags.Freeleech;
+ }
+
+ if (torrent.Scene)
+ {
+ flags |= IndexerFlags.Scene;
+ }
+
+ return flags;
+ }
+
private string GetDownloadUrl(int torrentId, bool canUseToken)
{
var url = new HttpUri(_settings.BaseUrl)
diff --git a/src/NzbDrone.Core/Indexers/Torznab/TorznabRssParser.cs b/src/NzbDrone.Core/Indexers/Torznab/TorznabRssParser.cs
index 7e8285883..f4d210a84 100644
--- a/src/NzbDrone.Core/Indexers/Torznab/TorznabRssParser.cs
+++ b/src/NzbDrone.Core/Indexers/Torznab/TorznabRssParser.cs
@@ -74,6 +74,18 @@ namespace NzbDrone.Core.Indexers.Torznab
return true;
}
+ protected override ReleaseInfo ProcessItem(XElement item, ReleaseInfo releaseInfo)
+ {
+ var torrentInfo = base.ProcessItem(item, releaseInfo) as TorrentInfo;
+
+ if (torrentInfo != null)
+ {
+ torrentInfo.IndexerFlags = GetFlags(item);
+ }
+
+ return torrentInfo;
+ }
+
protected override string GetInfoUrl(XElement item)
{
return ParseUrl(item.TryGetValue("comments").TrimEnd("#comments"));
@@ -180,6 +192,53 @@ namespace NzbDrone.Core.Indexers.Torznab
return base.GetPeers(item);
}
+ protected IndexerFlags GetFlags(XElement item)
+ {
+ IndexerFlags flags = 0;
+
+ var downloadFactor = TryGetFloatTorznabAttribute(item, "downloadvolumefactor", 1);
+ var uploadFactor = TryGetFloatTorznabAttribute(item, "uploadvolumefactor", 1);
+
+ if (downloadFactor == 0.5)
+ {
+ flags |= IndexerFlags.Halfleech;
+ }
+
+ if (downloadFactor == 0.75)
+ {
+ flags |= IndexerFlags.Freeleech25;
+ }
+
+ if (downloadFactor == 0.25)
+ {
+ flags |= IndexerFlags.Freeleech75;
+ }
+
+ if (downloadFactor == 0.0)
+ {
+ flags |= IndexerFlags.Freeleech;
+ }
+
+ if (uploadFactor == 2.0)
+ {
+ flags |= IndexerFlags.DoubleUpload;
+ }
+
+ var tags = TryGetMultipleTorznabAttributes(item, "tag");
+
+ if (tags.Any(t => t.EqualsIgnoreCase("internal")))
+ {
+ flags |= IndexerFlags.Internal;
+ }
+
+ if (tags.Any(t => t.EqualsIgnoreCase("scene")))
+ {
+ flags |= IndexerFlags.Scene;
+ }
+
+ return flags;
+ }
+
protected string TryGetTorznabAttribute(XElement item, string key, string defaultValue = "")
{
var attrElement = item.Elements(ns + "attr").FirstOrDefault(e => e.Attribute("name").Value.Equals(key, StringComparison.OrdinalIgnoreCase));
@@ -195,6 +254,13 @@ namespace NzbDrone.Core.Indexers.Torznab
return defaultValue;
}
+ protected float TryGetFloatTorznabAttribute(XElement item, string key, float defaultValue = 0)
+ {
+ var attr = TryGetTorznabAttribute(item, key, defaultValue.ToString());
+
+ return float.TryParse(attr, out var result) ? result : defaultValue;
+ }
+
protected List TryGetMultipleTorznabAttributes(XElement item, string key)
{
var attrElements = item.Elements(ns + "attr").Where(e => e.Attribute("name").Value.Equals(key, StringComparison.OrdinalIgnoreCase));
diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json
index 55fdd57f2..fd1161836 100644
--- a/src/NzbDrone.Core/Localization/Core/en.json
+++ b/src/NzbDrone.Core/Localization/Core/en.json
@@ -201,6 +201,7 @@
"Clear": "Clear",
"ClearBlocklist": "Clear blocklist",
"ClearBlocklistMessageText": "Are you sure you want to clear all items from the blocklist?",
+ "ClickToChangeIndexerFlags": "Click to change indexer flags",
"ClickToChangeQuality": "Click to change quality",
"ClickToChangeReleaseGroup": "Click to change release group",
"ClientPriority": "Client Priority",
@@ -257,6 +258,7 @@
"CustomFormats": "Custom Formats",
"CustomFormatsSettings": "Custom Formats Settings",
"CustomFormatsSettingsSummary": "Custom Formats and Settings",
+ "CustomFormatsSpecificationFlag": "Flag",
"CustomFormatsSpecificationRegularExpression": "Regular Expression",
"CustomFormatsSpecificationRegularExpressionHelpText": "Custom Format RegEx is Case Insensitive",
"Customformat": "Custom Format",
@@ -574,6 +576,7 @@
"Indexer": "Indexer",
"IndexerDownloadClientHealthCheckMessage": "Indexers with invalid download clients: {0}.",
"IndexerDownloadClientHelpText": "Specify which download client is used for grabs from this indexer",
+ "IndexerFlags": "Indexer Flags",
"IndexerIdHelpText": "Specify what indexer the profile applies to",
"IndexerIdHelpTextWarning": "Using a specific indexer with preferred words can lead to duplicate releases being grabbed",
"IndexerJackettAll": "Indexers using the unsupported Jackett 'all' endpoint: {0}",
@@ -901,6 +904,7 @@
"RegularExpressionsCanBeTested": "Regular expressions can be tested [here](http://regexstorm.net/tester).",
"RegularExpressionsTutorialLink": "More details on regular expressions can be found [here](https://www.regular-expressions.info/tutorial.html).",
"RejectionCount": "Rejection Count",
+ "Rejections": "Rejections",
"Release": " Release",
"ReleaseDate": "Release Date",
"ReleaseGroup": "Release Group",
@@ -1043,12 +1047,14 @@
"SelectAlbumRelease": "Select Album Release",
"SelectArtist": "Select Artist",
"SelectFolder": "Select Folder",
+ "SelectIndexerFlags": "Select Indexer Flags",
"SelectQuality": "Select Quality",
"SelectReleaseGroup": "Select Release Group",
"SelectTracks": "Select Tracks",
"SelectedCountArtistsSelectedInterp": "{selectedCount} Artist(s) Selected",
"SendAnonymousUsageData": "Send Anonymous Usage Data",
"SetAppTags": "Set {appName} Tags",
+ "SetIndexerFlags": "Set Indexer Flags",
"SetPermissions": "Set Permissions",
"SetPermissionsLinuxHelpText": "Should chmod be run when files are imported/renamed?",
"SetPermissionsLinuxHelpTextWarning": "If you're unsure what these settings do, do not alter them.",
diff --git a/src/NzbDrone.Core/MediaFiles/TrackFile.cs b/src/NzbDrone.Core/MediaFiles/TrackFile.cs
index de5d8a805..62273ec10 100644
--- a/src/NzbDrone.Core/MediaFiles/TrackFile.cs
+++ b/src/NzbDrone.Core/MediaFiles/TrackFile.cs
@@ -19,6 +19,7 @@ namespace NzbDrone.Core.MediaFiles
public string SceneName { get; set; }
public string ReleaseGroup { get; set; }
public QualityModel Quality { get; set; }
+ public IndexerFlags IndexerFlags { get; set; }
public MediaInfoModel MediaInfo { get; set; }
public int AlbumId { get; set; }
diff --git a/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs
index ba54e10c8..6c15d475e 100644
--- a/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs
+++ b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs
@@ -9,6 +9,7 @@ using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.Extras;
+using NzbDrone.Core.History;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Events;
@@ -40,6 +41,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
private readonly IRecycleBinProvider _recycleBinProvider;
private readonly IExtraService _extraService;
private readonly IDiskProvider _diskProvider;
+ private readonly IHistoryService _historyService;
private readonly IReleaseService _releaseService;
private readonly IEventAggregator _eventAggregator;
private readonly IManageCommandQueue _commandQueueManager;
@@ -57,6 +59,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
IRecycleBinProvider recycleBinProvider,
IExtraService extraService,
IDiskProvider diskProvider,
+ IHistoryService historyService,
IReleaseService releaseService,
IEventAggregator eventAggregator,
IManageCommandQueue commandQueueManager,
@@ -74,6 +77,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
_recycleBinProvider = recycleBinProvider;
_extraService = extraService;
_diskProvider = diskProvider;
+ _historyService = historyService;
_releaseService = releaseService;
_eventAggregator = eventAggregator;
_commandQueueManager = commandQueueManager;
@@ -197,6 +201,22 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
Tracks = localTrack.Tracks
};
+ if (downloadClientItem?.DownloadId.IsNotNullOrWhiteSpace() == true)
+ {
+ var grabHistory = _historyService.FindByDownloadId(downloadClientItem.DownloadId)
+ .OrderByDescending(h => h.Date)
+ .FirstOrDefault(h => h.EventType == EntityHistoryEventType.Grabbed);
+
+ if (Enum.TryParse(grabHistory?.Data.GetValueOrDefault("indexerFlags"), true, out IndexerFlags flags))
+ {
+ trackFile.IndexerFlags = flags;
+ }
+ }
+ else
+ {
+ trackFile.IndexerFlags = localTrack.IndexerFlags;
+ }
+
bool copyOnly;
switch (importMode)
{
diff --git a/src/NzbDrone.Core/MediaFiles/TrackImport/Manual/ManualImportFile.cs b/src/NzbDrone.Core/MediaFiles/TrackImport/Manual/ManualImportFile.cs
index 9faec9a65..9d1195cff 100644
--- a/src/NzbDrone.Core/MediaFiles/TrackImport/Manual/ManualImportFile.cs
+++ b/src/NzbDrone.Core/MediaFiles/TrackImport/Manual/ManualImportFile.cs
@@ -13,6 +13,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
public int AlbumReleaseId { get; set; }
public List TrackIds { get; set; }
public QualityModel Quality { get; set; }
+ public int IndexerFlags { get; set; }
public string DownloadId { get; set; }
public bool DisableReleaseSwitching { get; set; }
diff --git a/src/NzbDrone.Core/MediaFiles/TrackImport/Manual/ManualImportItem.cs b/src/NzbDrone.Core/MediaFiles/TrackImport/Manual/ManualImportItem.cs
index b96fbc045..43a15e9a8 100644
--- a/src/NzbDrone.Core/MediaFiles/TrackImport/Manual/ManualImportItem.cs
+++ b/src/NzbDrone.Core/MediaFiles/TrackImport/Manual/ManualImportItem.cs
@@ -27,6 +27,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
public string ReleaseGroup { get; set; }
public string DownloadId { get; set; }
public List CustomFormats { get; set; }
+ public int IndexerFlags { get; set; }
public IEnumerable Rejections { get; set; }
public ParsedTrackInfo Tags { get; set; }
public bool AdditionalFile { get; set; }
diff --git a/src/NzbDrone.Core/MediaFiles/TrackImport/Manual/ManualImportService.cs b/src/NzbDrone.Core/MediaFiles/TrackImport/Manual/ManualImportService.cs
index 0b8a18f6c..7cf6b7c85 100644
--- a/src/NzbDrone.Core/MediaFiles/TrackImport/Manual/ManualImportService.cs
+++ b/src/NzbDrone.Core/MediaFiles/TrackImport/Manual/ManualImportService.cs
@@ -293,6 +293,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
}
item.Quality = decision.Item.Quality;
+ item.IndexerFlags = (int)decision.Item.IndexerFlags;
item.Size = _diskProvider.GetFileSize(decision.Item.Path);
item.Rejections = decision.Rejections;
item.Tags = decision.Item.FileTrackInfo;
@@ -344,6 +345,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
Size = fileInfo.Length,
Modified = fileInfo.LastWriteTimeUtc,
Quality = file.Quality,
+ IndexerFlags = (IndexerFlags)file.IndexerFlags,
Artist = artist,
Album = album,
Release = release
diff --git a/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs b/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs
index 4749a30f6..824f6b9fc 100644
--- a/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs
+++ b/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs
@@ -75,6 +75,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
environmentVariables.Add("Lidarr_Release_Quality", remoteAlbum.ParsedAlbumInfo.Quality.Quality.Name);
environmentVariables.Add("Lidarr_Release_QualityVersion", remoteAlbum.ParsedAlbumInfo.Quality.Revision.Version.ToString());
environmentVariables.Add("Lidarr_Release_ReleaseGroup", releaseGroup ?? string.Empty);
+ environmentVariables.Add("Lidarr_Release_IndexerFlags", remoteAlbum.Release.IndexerFlags.ToString());
environmentVariables.Add("Lidarr_Download_Client", message.DownloadClientName ?? string.Empty);
environmentVariables.Add("Lidarr_Download_Client_Type", message.DownloadClientType ?? string.Empty);
environmentVariables.Add("Lidarr_Download_Id", message.DownloadId ?? string.Empty);
diff --git a/src/NzbDrone.Core/Parser/Model/LocalTrack.cs b/src/NzbDrone.Core/Parser/Model/LocalTrack.cs
index 1fc38c6ef..45bf44f31 100644
--- a/src/NzbDrone.Core/Parser/Model/LocalTrack.cs
+++ b/src/NzbDrone.Core/Parser/Model/LocalTrack.cs
@@ -26,6 +26,7 @@ namespace NzbDrone.Core.Parser.Model
public List