New: Rewrite Indexer Flags Implementation

pull/72/head
Qstick 4 years ago
parent cebdcd6065
commit dd66d7845c

@ -7,7 +7,7 @@ import { saveDimensions, setIsSidebarVisible } from 'Store/Actions/appActions';
import { fetchCustomFilters } from 'Store/Actions/customFilterActions'; import { fetchCustomFilters } from 'Store/Actions/customFilterActions';
import { fetchIndexers } from 'Store/Actions/indexerActions'; import { fetchIndexers } from 'Store/Actions/indexerActions';
import { fetchIndexerStatus } from 'Store/Actions/indexerStatusActions'; import { fetchIndexerStatus } from 'Store/Actions/indexerStatusActions';
import { fetchGeneralSettings, fetchIndexerCategories, fetchIndexerFlags, fetchLanguages, fetchUISettings } from 'Store/Actions/settingsActions'; import { fetchGeneralSettings, fetchIndexerCategories, fetchLanguages, fetchUISettings } from 'Store/Actions/settingsActions';
import { fetchStatus } from 'Store/Actions/systemActions'; import { fetchStatus } from 'Store/Actions/systemActions';
import { fetchTags } from 'Store/Actions/tagActions'; import { fetchTags } from 'Store/Actions/tagActions';
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector'; import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
@ -52,7 +52,6 @@ const selectIsPopulated = createSelector(
(state) => state.indexers.isPopulated, (state) => state.indexers.isPopulated,
(state) => state.indexerStatus.isPopulated, (state) => state.indexerStatus.isPopulated,
(state) => state.settings.indexerCategories.isPopulated, (state) => state.settings.indexerCategories.isPopulated,
(state) => state.settings.indexerFlags.isPopulated,
(state) => state.system.status.isPopulated, (state) => state.system.status.isPopulated,
( (
customFiltersIsPopulated, customFiltersIsPopulated,
@ -63,7 +62,6 @@ const selectIsPopulated = createSelector(
indexersIsPopulated, indexersIsPopulated,
indexerStatusIsPopulated, indexerStatusIsPopulated,
indexerCategoriesIsPopulated, indexerCategoriesIsPopulated,
indexerFlagsIsPopulated,
systemStatusIsPopulated systemStatusIsPopulated
) => { ) => {
return ( return (
@ -75,7 +73,6 @@ const selectIsPopulated = createSelector(
indexersIsPopulated && indexersIsPopulated &&
indexerStatusIsPopulated && indexerStatusIsPopulated &&
indexerCategoriesIsPopulated && indexerCategoriesIsPopulated &&
indexerFlagsIsPopulated &&
systemStatusIsPopulated systemStatusIsPopulated
); );
} }
@ -90,7 +87,6 @@ const selectErrors = createSelector(
(state) => state.indexers.error, (state) => state.indexers.error,
(state) => state.indexerStatus.error, (state) => state.indexerStatus.error,
(state) => state.settings.indexerCategories.error, (state) => state.settings.indexerCategories.error,
(state) => state.settings.indexerFlags.error,
(state) => state.system.status.error, (state) => state.system.status.error,
( (
customFiltersError, customFiltersError,
@ -101,7 +97,6 @@ const selectErrors = createSelector(
indexersError, indexersError,
indexerStatusError, indexerStatusError,
indexerCategoriesError, indexerCategoriesError,
indexerFlagsError,
systemStatusError systemStatusError
) => { ) => {
const hasError = !!( const hasError = !!(
@ -113,7 +108,6 @@ const selectErrors = createSelector(
indexersError || indexersError ||
indexerStatusError || indexerStatusError ||
indexerCategoriesError || indexerCategoriesError ||
indexerFlagsError ||
systemStatusError systemStatusError
); );
@ -127,7 +121,6 @@ const selectErrors = createSelector(
indexersError, indexersError,
indexerStatusError, indexerStatusError,
indexerCategoriesError, indexerCategoriesError,
indexerFlagsError,
systemStatusError systemStatusError
}; };
} }
@ -178,9 +171,6 @@ function createMapDispatchToProps(dispatch, props) {
dispatchFetchIndexerCategories() { dispatchFetchIndexerCategories() {
dispatch(fetchIndexerCategories()); dispatch(fetchIndexerCategories());
}, },
dispatchFetchIndexerFlags() {
dispatch(fetchIndexerFlags());
},
dispatchFetchUISettings() { dispatchFetchUISettings() {
dispatch(fetchUISettings()); dispatch(fetchUISettings());
}, },
@ -220,7 +210,6 @@ class PageConnector extends Component {
this.props.dispatchFetchIndexers(); this.props.dispatchFetchIndexers();
this.props.dispatchFetchIndexerStatus(); this.props.dispatchFetchIndexerStatus();
this.props.dispatchFetchIndexerCategories(); this.props.dispatchFetchIndexerCategories();
this.props.dispatchFetchIndexerFlags();
this.props.dispatchFetchUISettings(); this.props.dispatchFetchUISettings();
this.props.dispatchFetchGeneralSettings(); this.props.dispatchFetchGeneralSettings();
this.props.dispatchFetchStatus(); this.props.dispatchFetchStatus();
@ -246,7 +235,6 @@ class PageConnector extends Component {
dispatchFetchIndexers, dispatchFetchIndexers,
dispatchFetchIndexerStatus, dispatchFetchIndexerStatus,
dispatchFetchIndexerCategories, dispatchFetchIndexerCategories,
dispatchFetchIndexerFlags,
dispatchFetchUISettings, dispatchFetchUISettings,
dispatchFetchGeneralSettings, dispatchFetchGeneralSettings,
dispatchFetchStatus, dispatchFetchStatus,
@ -287,7 +275,6 @@ PageConnector.propTypes = {
dispatchFetchIndexers: PropTypes.func.isRequired, dispatchFetchIndexers: PropTypes.func.isRequired,
dispatchFetchIndexerStatus: PropTypes.func.isRequired, dispatchFetchIndexerStatus: PropTypes.func.isRequired,
dispatchFetchIndexerCategories: PropTypes.func.isRequired, dispatchFetchIndexerCategories: PropTypes.func.isRequired,
dispatchFetchIndexerFlags: PropTypes.func.isRequired,
dispatchFetchUISettings: PropTypes.func.isRequired, dispatchFetchUISettings: PropTypes.func.isRequired,
dispatchFetchGeneralSettings: PropTypes.func.isRequired, dispatchFetchGeneralSettings: PropTypes.func.isRequired,
dispatchFetchStatus: PropTypes.func.isRequired, dispatchFetchStatus: PropTypes.func.isRequired,

@ -10,6 +10,7 @@ import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import formatDateTime from 'Utilities/Date/formatDateTime'; import formatDateTime from 'Utilities/Date/formatDateTime';
import formatAge from 'Utilities/Number/formatAge'; import formatAge from 'Utilities/Number/formatAge';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
import titleCase from 'Utilities/String/titleCase';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
import CategoryLabel from './CategoryLabel'; import CategoryLabel from './CategoryLabel';
import Peers from './Peers'; import Peers from './Peers';
@ -249,7 +250,7 @@ class SearchIndexRow extends Component {
indexerFlags.map((flag, index) => { indexerFlags.map((flag, index) => {
return ( return (
<li key={index}> <li key={index}>
{flag} {titleCase(flag)}
</li> </li>
); );
}) })

@ -1,48 +0,0 @@
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: {
}
};

@ -6,7 +6,6 @@ import development from './Settings/development';
import downloadClients from './Settings/downloadClients'; import downloadClients from './Settings/downloadClients';
import general from './Settings/general'; import general from './Settings/general';
import indexerCategories from './Settings/indexerCategories'; import indexerCategories from './Settings/indexerCategories';
import indexerFlags from './Settings/indexerFlags';
import languages from './Settings/languages'; import languages from './Settings/languages';
import notifications from './Settings/notifications'; import notifications from './Settings/notifications';
import ui from './Settings/ui'; import ui from './Settings/ui';
@ -14,7 +13,6 @@ import ui from './Settings/ui';
export * from './Settings/downloadClients'; export * from './Settings/downloadClients';
export * from './Settings/general'; export * from './Settings/general';
export * from './Settings/indexerCategories'; export * from './Settings/indexerCategories';
export * from './Settings/indexerFlags';
export * from './Settings/languages'; export * from './Settings/languages';
export * from './Settings/notifications'; export * from './Settings/notifications';
export * from './Settings/applications'; export * from './Settings/applications';
@ -35,7 +33,6 @@ export const defaultState = {
downloadClients: downloadClients.defaultState, downloadClients: downloadClients.defaultState,
general: general.defaultState, general: general.defaultState,
indexerCategories: indexerCategories.defaultState, indexerCategories: indexerCategories.defaultState,
indexerFlags: indexerFlags.defaultState,
languages: languages.defaultState, languages: languages.defaultState,
notifications: notifications.defaultState, notifications: notifications.defaultState,
applications: applications.defaultState, applications: applications.defaultState,
@ -64,7 +61,6 @@ export const actionHandlers = handleThunks({
...downloadClients.actionHandlers, ...downloadClients.actionHandlers,
...general.actionHandlers, ...general.actionHandlers,
...indexerCategories.actionHandlers, ...indexerCategories.actionHandlers,
...indexerFlags.actionHandlers,
...languages.actionHandlers, ...languages.actionHandlers,
...notifications.actionHandlers, ...notifications.actionHandlers,
...applications.actionHandlers, ...applications.actionHandlers,
@ -84,7 +80,6 @@ export const reducers = createHandleActions({
...downloadClients.reducers, ...downloadClients.reducers,
...general.reducers, ...general.reducers,
...indexerCategories.reducers, ...indexerCategories.reducers,
...indexerFlags.reducers,
...languages.reducers, ...languages.reducers,
...notifications.reducers, ...notifications.reducers,
...applications.reducers, ...applications.reducers,

@ -64,7 +64,7 @@ namespace NzbDrone.Core.Test.IndexerTests.PTPTests
first.Peers.Should().Be(28); first.Peers.Should().Be(28);
first.Seeders.Should().Be(26); first.Seeders.Should().Be(26);
torrents.Any(t => t.IndexerFlags.HasFlag(IndexerFlags.G_Freeleech)).Should().Be(true); torrents.Any(t => t.IndexerFlags.Contains(IndexerFlag.Scene)).Should().Be(true);
} }
} }
} }

@ -87,6 +87,7 @@ namespace NzbDrone.Core.IndexerSearch
r.Size == null ? null : new XAttribute("length", r.Size), r.Size == null ? null : new XAttribute("length", r.Size),
new XAttribute("type", protocol == DownloadProtocol.Torrent ? "application/x-bittorrent" : "application/x-nzb")), new XAttribute("type", protocol == DownloadProtocol.Torrent ? "application/x-bittorrent" : "application/x-nzb")),
r.Category == null ? null : from c in r.Category select GetNabElement("category", c.Id, protocol), r.Category == null ? null : from c in r.Category select GetNabElement("category", c.Id, protocol),
r.IndexerFlags == null ? null : from f in r.IndexerFlags select GetNabElement("tag", f.Name, protocol),
GetNabElement("rageid", r.TvRageId, protocol), GetNabElement("rageid", r.TvRageId, protocol),
GetNabElement("thetvdb", r.TvdbId, protocol), GetNabElement("thetvdb", r.TvdbId, protocol),
GetNabElement("imdb", r.ImdbId.ToString("D7"), protocol), GetNabElement("imdb", r.ImdbId.ToString("D7"), protocol),

@ -51,6 +51,10 @@ namespace NzbDrone.Core.Indexers.FileList
BookSearchParams = new List<BookSearchParam> BookSearchParams = new List<BookSearchParam>
{ {
BookSearchParam.Q BookSearchParam.Q
},
Flags = new List<IndexerFlag>
{
IndexerFlag.FreeLeech
} }
}; };

@ -36,11 +36,11 @@ namespace NzbDrone.Core.Indexers.FileList
{ {
var id = result.Id; var id = result.Id;
IndexerFlags flags = 0; var flags = new List<IndexerFlag>();
if (result.FreeLeech) if (result.FreeLeech)
{ {
flags |= IndexerFlags.G_Freeleech; flags.Add(IndexerFlag.FreeLeech);
} }
var imdbId = 0; var imdbId = 0;

@ -55,16 +55,16 @@ namespace NzbDrone.Core.Indexers.HDBits
var id = result.Id; var id = result.Id;
var internalRelease = result.TypeOrigin == 1 ? true : false; var internalRelease = result.TypeOrigin == 1 ? true : false;
IndexerFlags flags = 0; var flags = new List<IndexerFlag>();
if (result.FreeLeech == "yes") if (result.FreeLeech == "yes")
{ {
flags |= IndexerFlags.G_Freeleech; flags.Add(IndexerFlag.FreeLeech);
} }
if (internalRelease) if (internalRelease)
{ {
flags |= IndexerFlags.HDB_Internal; flags.Add(IndexerFlag.Internal);
} }
torrentInfos.Add(new HDBitsInfo() torrentInfos.Add(new HDBitsInfo()

@ -52,6 +52,12 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
MovieSearchParams = new List<MovieSearchParam> MovieSearchParams = new List<MovieSearchParam>
{ {
MovieSearchParam.Q, MovieSearchParam.ImdbId MovieSearchParam.Q, MovieSearchParam.ImdbId
},
Flags = new List<IndexerFlag>
{
IndexerFlag.FreeLeech,
PassThePopcornFlag.Golden,
PassThePopcornFlag.Approved
} }
}; };
@ -74,7 +80,13 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
public override IParseIndexerResponse GetParser() public override IParseIndexerResponse GetParser()
{ {
return new PassThePopcornParser(BaseUrl, _logger); return new PassThePopcornParser(BaseUrl, Capabilities, _logger);
}
} }
public class PassThePopcornFlag : IndexerFlag
{
public static IndexerFlag Golden => new IndexerFlag("golden", "Release follows Golden Popcorn quality rules");
public static IndexerFlag Approved => new IndexerFlag("approved", "Release approved by PTP");
} }
} }

@ -13,10 +13,12 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
public class PassThePopcornParser : IParseIndexerResponse public class PassThePopcornParser : IParseIndexerResponse
{ {
private readonly string _baseUrl; private readonly string _baseUrl;
private readonly IndexerCapabilities _capabilities;
private readonly Logger _logger; private readonly Logger _logger;
public PassThePopcornParser(string baseUrl, Logger logger) public PassThePopcornParser(string baseUrl, IndexerCapabilities capabilities, Logger logger)
{ {
_baseUrl = baseUrl; _baseUrl = baseUrl;
_capabilities = capabilities;
_logger = logger; _logger = logger;
} }
@ -63,26 +65,27 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
{ {
var id = torrent.Id; var id = torrent.Id;
var title = torrent.ReleaseName; var title = torrent.ReleaseName;
IndexerFlags flags = 0;
var flags = new List<IndexerFlag>();
if (torrent.GoldenPopcorn) if (torrent.GoldenPopcorn)
{ {
flags |= IndexerFlags.PTP_Golden; //title = $"{title} 🍿"; flags.Add(PassThePopcornFlag.Golden);
} }
if (torrent.Checked) if (torrent.Checked)
{ {
flags |= IndexerFlags.PTP_Approved; //title = $"{title} ✔"; flags.Add(PassThePopcornFlag.Approved); //title = $"{title} ✔";
} }
if (torrent.FreeleechType == "Freeleech") if (torrent.FreeleechType == "Freeleech")
{ {
flags |= IndexerFlags.G_Freeleech; flags.Add(IndexerFlag.FreeLeech);
} }
if (torrent.Scene) if (torrent.Scene)
{ {
flags |= IndexerFlags.G_Scene; flags.Add(IndexerFlag.Scene);
} }
var free = !(torrent.FreeleechType is null); var free = !(torrent.FreeleechType is null);

@ -173,9 +173,9 @@ namespace NzbDrone.Core.Indexers.Torznab
return base.GetPeers(item); return base.GetPeers(item);
} }
protected IndexerFlags GetFlags(XElement item) protected List<IndexerFlag> GetFlags(XElement item)
{ {
IndexerFlags flags = 0; var flags = new List<IndexerFlag>();
var downloadFactor = TryGetFloatTorznabAttribute(item, "downloadvolumefactor", 1); var downloadFactor = TryGetFloatTorznabAttribute(item, "downloadvolumefactor", 1);
@ -183,17 +183,17 @@ namespace NzbDrone.Core.Indexers.Torznab
if (uploadFactor == 2) if (uploadFactor == 2)
{ {
flags |= IndexerFlags.G_DoubleUpload; flags.Add(IndexerFlag.DoubleUpload);
} }
if (downloadFactor == 0.5) if (downloadFactor == 0.5)
{ {
flags |= IndexerFlags.G_Halfleech; flags.Add(IndexerFlag.HalfLeech);
} }
if (downloadFactor == 0.0) if (downloadFactor == 0.0)
{ {
flags |= IndexerFlags.G_Freeleech; flags.Add(IndexerFlag.FreeLeech);
} }
return flags; return flags;

@ -83,6 +83,7 @@ namespace NzbDrone.Core.Indexers
public bool BookSearchAuthorAvailable => BookSearchParams.Contains(BookSearchParam.Author); public bool BookSearchAuthorAvailable => BookSearchParams.Contains(BookSearchParam.Author);
public readonly IndexerCapabilitiesCategories Categories; public readonly IndexerCapabilitiesCategories Categories;
public List<IndexerFlag> Flags;
public IndexerCapabilities() public IndexerCapabilities()
{ {
@ -92,6 +93,7 @@ namespace NzbDrone.Core.Indexers
MusicSearchParams = new List<MusicSearchParam>(); MusicSearchParams = new List<MusicSearchParam>();
BookSearchParams = new List<BookSearchParam>(); BookSearchParams = new List<BookSearchParam>();
Categories = new IndexerCapabilitiesCategories(); Categories = new IndexerCapabilitiesCategories();
Flags = new List<IndexerFlag>();
LimitsDefault = 100; LimitsDefault = 100;
LimitsMax = 100; LimitsMax = 100;
} }
@ -386,7 +388,12 @@ namespace NzbDrone.Core.Indexers
from sc in c.SubCategories from sc in c.SubCategories
select new XElement("subcat", select new XElement("subcat",
new XAttribute("id", sc.Id), new XAttribute("id", sc.Id),
new XAttribute("name", sc.Name)))))); new XAttribute("name", sc.Name)))),
new XElement("tags",
from c in Flags
select new XElement("tag",
new XAttribute("name", c.Name),
new XAttribute("description", c.Description)))));
return xdoc; return xdoc;
} }

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NzbDrone.Core.Indexers
{
public class IndexerFlag : IEquatable<IndexerFlag>
{
public string Name { get; set; }
public string Description { get; set; }
public IndexerFlag()
{
}
public IndexerFlag(string name, string description)
{
Name = name;
Description = description;
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
public bool Equals(IndexerFlag other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Name.Equals(other.Name);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return Equals(obj as IndexerFlag);
}
public static bool operator ==(IndexerFlag left, IndexerFlag right)
{
return Equals(left, right);
}
public static bool operator !=(IndexerFlag left, IndexerFlag right)
{
return !Equals(left, right);
}
public static IndexerFlag Internal => new IndexerFlag("internal", "Uploader is an internal release group");
public static IndexerFlag FreeLeech => new IndexerFlag("freeleech", "Release doesn't count torward ratio");
public static IndexerFlag HalfLeech => new IndexerFlag("halfleech", "Release counts 50% to ratio");
public static IndexerFlag Scene => new IndexerFlag("scene", "Uploader follows scene rules");
public static IndexerFlag DoubleUpload => new IndexerFlag("doubleupload", "Seeding counts double for release");
}
}

@ -34,7 +34,7 @@ namespace NzbDrone.Core.Parser.Model
public string Resolution { get; set; } public string Resolution { get; set; }
public ICollection<IndexerCategory> Category { get; set; } public ICollection<IndexerCategory> Category { get; set; }
public IndexerFlags IndexerFlags { get; set; } public ICollection<IndexerFlag> IndexerFlags { get; set; }
public int Age public int Age
{ {
@ -134,20 +134,4 @@ namespace NzbDrone.Core.Parser.Model
public static long BytesFromKB(float kb) => (long)(kb * 1024f); public static long BytesFromKB(float kb) => (long)(kb * 1024f);
} }
[Flags]
public enum IndexerFlags
{
G_Freeleech = 1, //General
G_Halfleech = 2, //General, only 1/2 of download counted
G_DoubleUpload = 4, //General
PTP_Golden = 8, //PTP
PTP_Approved = 16, //PTP
HDB_Internal = 32, //HDBits, internal
AHD_Internal = 64, // AHD, internal
G_Scene = 128, //General, the torrent comes from the "scene"
G_Freeleech75 = 256, //Currently only used for AHD, signifies a torrent counts towards 75 percent of your download quota.
G_Freeleech25 = 512, //Currently only used for AHD, signifies a torrent counts towards 25 percent of your download quota.
AHD_UserRelease = 1024 // AHD, internal
}
} }

@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using NzbDrone.Core.Parser.Model;
using Prowlarr.Http;
namespace Prowlarr.Api.V1.Indexers
{
[V1ApiController]
public class IndexerFlagController : Controller
{
[HttpGet]
public List<IndexerFlagResource> GetAll()
{
return Enum.GetValues(typeof(IndexerFlags)).Cast<IndexerFlags>().Select(f => new IndexerFlagResource
{
Id = (int)f,
Name = f.ToString()
}).ToList();
}
}
}

@ -1,13 +0,0 @@
using Newtonsoft.Json;
using Prowlarr.Http.REST;
namespace Prowlarr.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();
}
}

@ -43,7 +43,7 @@ namespace Prowlarr.Api.V1.Search
{ {
var releaseInfo = model; var releaseInfo = model;
var torrentInfo = (model as TorrentInfo) ?? new TorrentInfo(); var torrentInfo = (model as TorrentInfo) ?? new TorrentInfo();
var indexerFlags = torrentInfo.IndexerFlags.ToString().Split(new string[] { ", " }, StringSplitOptions.None).Where(x => x != "0"); var indexerFlags = torrentInfo.IndexerFlags.Select(f => f.Name);
// 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?) // 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 SearchResource return new SearchResource

Loading…
Cancel
Save