diff --git a/frontend/src/Indexer/Index/Table/IndexerIndexRow.js b/frontend/src/Indexer/Index/Table/IndexerIndexRow.js index 182cf4d31..9609ff4ec 100644 --- a/frontend/src/Indexer/Index/Table/IndexerIndexRow.js +++ b/frontend/src/Indexer/Index/Table/IndexerIndexRow.js @@ -9,6 +9,7 @@ import TagListConnector from 'Components/TagListConnector'; import { icons } from 'Helpers/Props'; import DeleteIndexerModal from 'Indexer/Delete/DeleteIndexerModal'; import EditIndexerModalConnector from 'Indexer/Edit/EditIndexerModalConnector'; +import IndexerInfoModal from 'Indexer/Info/IndexerInfoModal'; import titleCase from 'Utilities/String/titleCase'; import translate from 'Utilities/String/translate'; import CapabilitiesLabel from './CapabilitiesLabel'; @@ -26,7 +27,8 @@ class IndexerIndexRow extends Component { this.state = { isEditIndexerModalOpen: false, - isDeleteMovieModalOpen: false + isDeleteMovieModalOpen: false, + isIndexerInfoModalOpen: false }; } @@ -34,10 +36,18 @@ class IndexerIndexRow extends Component { this.setState({ isEditIndexerModalOpen: true }); } + onIndexerInfoPress = () => { + this.setState({ isIndexerInfoModalOpen: true }); + } + onEditIndexerModalClose = () => { this.setState({ isEditIndexerModalOpen: false }); } + onIndexerInfoModalClose = () => { + this.setState({ isIndexerInfoModalOpen: false }); + } + onDeleteMoviePress = () => { this.setState({ isEditIndexerModalOpen: false, @@ -81,7 +91,8 @@ class IndexerIndexRow extends Component { const { isEditIndexerModalOpen, - isDeleteMovieModalOpen + isDeleteMovieModalOpen, + isIndexerInfoModalOpen } = this.state; return ( @@ -215,6 +226,12 @@ class IndexerIndexRow extends Component { key={column.name} className={styles[column.name]} > + + + + + + + ); +} + +IndexerInfoModal.propTypes = { + isOpen: PropTypes.bool.isRequired, + onModalClose: PropTypes.func.isRequired +}; + +export default IndexerInfoModal; diff --git a/frontend/src/Indexer/Info/IndexerInfoModalContent.css b/frontend/src/Indexer/Info/IndexerInfoModalContent.css new file mode 100644 index 000000000..383f08afd --- /dev/null +++ b/frontend/src/Indexer/Info/IndexerInfoModalContent.css @@ -0,0 +1,5 @@ +.description { + composes: description from '~Components/DescriptionList/DescriptionListItemDescription.css'; + + overflow-wrap: break-word; +} diff --git a/frontend/src/Indexer/Info/IndexerInfoModalContent.js b/frontend/src/Indexer/Info/IndexerInfoModalContent.js new file mode 100644 index 000000000..3788717b4 --- /dev/null +++ b/frontend/src/Indexer/Info/IndexerInfoModalContent.js @@ -0,0 +1,82 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import DescriptionList from 'Components/DescriptionList/DescriptionList'; +import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem'; +import DescriptionListItemDescription from 'Components/DescriptionList/DescriptionListItemDescription'; +import DescriptionListItemTitle from 'Components/DescriptionList/DescriptionListItemTitle'; +import Link from 'Components/Link/Link'; +import ModalBody from 'Components/Modal/ModalBody'; +import ModalContent from 'Components/Modal/ModalContent'; +import ModalHeader from 'Components/Modal/ModalHeader'; +import translate from 'Utilities/String/translate'; +import styles from './IndexerInfoModalContent.css'; + +function IndexerInfoModalContent(props) { + const { + id, + name, + description, + encoding, + language, + baseUrl, + protocol, + onModalClose + } = props; + + return ( + + + {`${name}`} + + + + + + + + + + Indexer Site + + {baseUrl} + + + {protocol === 'usenet' ? 'Newznab' : 'Torznab'} Url + + {`${window.Prowlarr.apiRoot}/indexer/${id}/newznab`} + + + + + + ); +} + +IndexerInfoModalContent.propTypes = { + id: PropTypes.number.isRequired, + name: PropTypes.string.isRequired, + description: PropTypes.string.isRequired, + encoding: PropTypes.string.isRequired, + language: PropTypes.string.isRequired, + baseUrl: PropTypes.string.isRequired, + protocol: PropTypes.string.isRequired, + onModalClose: PropTypes.func.isRequired +}; + +export default IndexerInfoModalContent; diff --git a/frontend/src/Indexer/Info/IndexerInfoModalContentConnector.js b/frontend/src/Indexer/Info/IndexerInfoModalContentConnector.js new file mode 100644 index 000000000..28d2bd1fa --- /dev/null +++ b/frontend/src/Indexer/Info/IndexerInfoModalContentConnector.js @@ -0,0 +1,41 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import createIndexerSelector from 'Store/Selectors/createIndexerSelector'; +import IndexerInfoModalContent from './IndexerInfoModalContent'; + +function createMapStateToProps() { + return createSelector( + (state) => state.settings.advancedSettings, + createIndexerSelector(), + (advancedSettings, indexer) => { + console.log(indexer); + return { + advancedSettings, + ...indexer + }; + } + ); +} + +class IndexerInfoModalContentConnector extends Component { + + // + // Render + + render() { + return ( + + ); + } +} + +IndexerInfoModalContentConnector.propTypes = { + indexerId: PropTypes.number, + onModalClose: PropTypes.func.isRequired +}; + +export default connect(createMapStateToProps)(IndexerInfoModalContentConnector); diff --git a/frontend/src/Store/Selectors/createIndexerSelector.js b/frontend/src/Store/Selectors/createIndexerSelector.js index 5a6b7bfd7..86a9fe1c1 100644 --- a/frontend/src/Store/Selectors/createIndexerSelector.js +++ b/frontend/src/Store/Selectors/createIndexerSelector.js @@ -5,9 +5,9 @@ function createIndexerSelector() { (state, { indexerId }) => indexerId, (state) => state.indexers.itemMap, (state) => state.indexers.items, - (indexerId, itemMap, allMovies) => { - if (allMovies && itemMap && indexerId in itemMap) { - return allMovies[itemMap[indexerId]]; + (indexerId, itemMap, allIndexers) => { + if (allIndexers && itemMap && indexerId in itemMap) { + return allIndexers[itemMap[indexerId]]; } return undefined; } diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index 4284095e2..70e718ed3 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -41,6 +41,9 @@ namespace NzbDrone.Core.Datastore Mapper.Entity("Indexers").RegisterModel() .Ignore(x => x.ImplementationName) + .Ignore(i => i.Description) + .Ignore(i => i.Language) + .Ignore(i => i.Encoding) .Ignore(i => i.BaseUrl) .Ignore(i => i.Protocol) .Ignore(i => i.Privacy) diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index f9ae906cc..c0cf256b0 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -128,6 +128,11 @@ namespace NzbDrone.Core.IndexerVersions }; } + if (definition.Encoding == null) + { + definition.Encoding = "UTF-8"; + } + if (definition.Login != null && definition.Login.Method == null) { definition.Login.Method = "form"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/AlphaRatio.cs b/src/NzbDrone.Core/Indexers/Definitions/AlphaRatio.cs index 881c5eadf..3422e8a0a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AlphaRatio.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AlphaRatio.cs @@ -10,6 +10,7 @@ namespace NzbDrone.Core.Indexers.Definitions { public override string Name => "AlphaRatio"; public override string BaseUrl => "https://alpharatio.cc/"; + public override string Description => "AlphaRatio(AR) is a Private Torrent Tracker for 0DAY / GENERAL"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public AlphaRatio(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index dbee62d22..725f422c7 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -33,6 +33,12 @@ namespace NzbDrone.Core.Indexers public override bool SupportsSearch => true; public override bool SupportsRedirect => false; + public override Encoding Encoding => Encoding.UTF8; + public override string Language => "en-US"; + + //TODO Remove this once we catch up on individual indexers + public override string Description => ""; + public override bool FollowRedirect => false; public override IndexerCapabilities Capabilities { get; protected set; } public virtual int PageSize => 0; diff --git a/src/NzbDrone.Core/Indexers/IIndexer.cs b/src/NzbDrone.Core/Indexers/IIndexer.cs index dfca11891..aa7c5d9c0 100644 --- a/src/NzbDrone.Core/Indexers/IIndexer.cs +++ b/src/NzbDrone.Core/Indexers/IIndexer.cs @@ -1,4 +1,5 @@ using System; +using System.Text; using System.Threading.Tasks; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.ThingiProvider; @@ -13,6 +14,9 @@ namespace NzbDrone.Core.Indexers IndexerCapabilities Capabilities { get; } string BaseUrl { get; } + string Description { get; } + Encoding Encoding { get; } + string Language { get; } DownloadProtocol Protocol { get; } IndexerPrivacy Privacy { get; } diff --git a/src/NzbDrone.Core/Indexers/IndexerBase.cs b/src/NzbDrone.Core/Indexers/IndexerBase.cs index ef416a735..e6feea055 100644 --- a/src/NzbDrone.Core/Indexers/IndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/IndexerBase.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Threading.Tasks; using FluentValidation.Results; using NLog; @@ -21,6 +22,9 @@ namespace NzbDrone.Core.Indexers public abstract string Name { get; } public abstract string BaseUrl { get; } + public abstract string Description { get; } + public abstract Encoding Encoding { get; } + public abstract string Language { get; } public abstract bool FollowRedirect { get; } public abstract DownloadProtocol Protocol { get; } public abstract IndexerPrivacy Privacy { get; } diff --git a/src/NzbDrone.Core/Indexers/IndexerDefinition.cs b/src/NzbDrone.Core/Indexers/IndexerDefinition.cs index f6808889d..3c9982a1e 100644 --- a/src/NzbDrone.Core/Indexers/IndexerDefinition.cs +++ b/src/NzbDrone.Core/Indexers/IndexerDefinition.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Text; using NzbDrone.Core.Indexers.Cardigann; using NzbDrone.Core.ThingiProvider; @@ -8,6 +9,9 @@ namespace NzbDrone.Core.Indexers public class IndexerDefinition : ProviderDefinition { public string BaseUrl { get; set; } + public string Description { get; set; } + public Encoding Encoding { get; set; } + public string Language { get; set; } public DownloadProtocol Protocol { get; set; } public IndexerPrivacy Privacy { get; set; } public bool SupportsRss { get; set; } diff --git a/src/NzbDrone.Core/Indexers/IndexerFactory.cs b/src/NzbDrone.Core/Indexers/IndexerFactory.cs index 4826a8fad..8dc8065e1 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFactory.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFactory.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using FluentValidation.Results; using NLog; using NzbDrone.Core.Indexers.Cardigann; @@ -90,6 +91,9 @@ namespace NzbDrone.Core.Indexers } definition.BaseUrl = defFile.Links.First(); + definition.Description = defFile.Description; + definition.Language = defFile.Language; + definition.Encoding = Encoding.GetEncoding(defFile.Encoding); definition.Privacy = defFile.Type == "private" ? IndexerPrivacy.Private : IndexerPrivacy.Public; definition.Capabilities = new IndexerCapabilities(); definition.Capabilities.ParseCardigannSearchModes(defFile.Caps.Modes); @@ -172,6 +176,9 @@ namespace NzbDrone.Core.Indexers { definition.BaseUrl = provider.BaseUrl; definition.Privacy = provider.Privacy; + definition.Description = provider.Description; + definition.Encoding = provider.Encoding; + definition.Language = provider.Language; definition.Capabilities = provider.Capabilities; } } diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs index c18632a35..98005fc07 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using NzbDrone.Common.Extensions; using NzbDrone.Core.Annotations; using NzbDrone.Core.Indexers; @@ -13,6 +14,9 @@ namespace Prowlarr.Api.V1.Indexers public class IndexerResource : ProviderResource { public string BaseUrl { get; set; } + public string Description { get; set; } + public string Language { get; set; } + public string Encoding { get; set; } public bool Enable { get; set; } public bool Redirect { get; set; } public bool SupportsRss { get; set; } @@ -62,6 +66,9 @@ namespace Prowlarr.Api.V1.Indexers } resource.BaseUrl = definition.BaseUrl; + resource.Description = definition.Description; + resource.Language = definition.Language; + resource.Encoding = definition.Encoding.EncodingName; resource.Enable = definition.Enable; resource.Redirect = definition.Redirect; resource.SupportsRss = definition.SupportsRss;