From 9fe13a2d14d661f332379e58b1b1254c4651533e Mon Sep 17 00:00:00 2001 From: Qstick Date: Sun, 23 Jan 2022 23:42:41 -0600 Subject: [PATCH] New: Custom Formats Co-Authored-By: ta264 --- frontend/build/webpack.config.js | 3 +- .../src/Activity/Blocklist/BlocklistRow.js | 13 + .../History/Details/HistoryDetails.js | 43 +- frontend/src/Activity/History/HistoryRow.css | 6 + frontend/src/Activity/History/HistoryRow.js | 25 + frontend/src/Activity/Queue/QueueRow.js | 13 + frontend/src/Album/AlbumFormats.js | 33 ++ frontend/src/App/AppRoutes.js | 6 + .../src/Components/Form/FormInputGroup.js | 4 + frontend/src/Components/Form/TextArea.css | 19 + frontend/src/Components/Form/TextArea.js | 172 +++++++ .../Components/Form/TextTagInputConnector.js | 6 +- .../src/Components/Link/ClipboardButton.js | 16 +- .../Components/Page/Sidebar/PageSidebar.js | 4 + .../Table/TableOptions/TableOptionsModal.js | 4 +- frontend/src/Helpers/Props/icons.js | 2 + frontend/src/Helpers/Props/inputTypes.js | 2 + .../InteractiveImportModalContent.js | 9 + .../Interactive/InteractiveImportRow.css | 4 + .../Interactive/InteractiveImportRow.js | 24 +- .../InteractiveSearch/InteractiveSearch.js | 4 +- .../InteractiveSearchRow.css | 2 +- .../InteractiveSearch/InteractiveSearchRow.js | 20 +- .../CustomFormatSettingsConnector.js | 32 ++ .../CustomFormats/CustomFormat.css | 49 ++ .../CustomFormats/CustomFormat.js | 174 +++++++ .../CustomFormats/CustomFormats.css | 21 + .../CustomFormats/CustomFormats.js | 115 +++++ .../CustomFormats/CustomFormatsConnector.js | 63 +++ .../CustomFormats/EditCustomFormatModal.js | 61 +++ .../EditCustomFormatModalConnector.js | 43 ++ .../EditCustomFormatModalContent.css | 27 ++ .../EditCustomFormatModalContent.js | 256 +++++++++++ .../EditCustomFormatModalContentConnector.js | 102 +++++ .../CustomFormats/ExportCustomFormatModal.js | 61 +++ .../ExportCustomFormatModalContent.css | 5 + .../ExportCustomFormatModalContent.js | 84 ++++ ...ExportCustomFormatModalContentConnector.js | 83 ++++ .../CustomFormats/ImportCustomFormatModal.js | 61 +++ .../ImportCustomFormatModalContent.css | 5 + .../ImportCustomFormatModalContent.js | 151 ++++++ ...ImportCustomFormatModalContentConnector.js | 145 ++++++ .../Specifications/AddSpecificationItem.css | 44 ++ .../Specifications/AddSpecificationItem.js | 110 +++++ .../Specifications/AddSpecificationModal.js | 25 + .../AddSpecificationModalContent.css | 5 + .../AddSpecificationModalContent.js | 101 ++++ .../AddSpecificationModalContentConnector.js | 70 +++ .../AddSpecificationPresetMenuItem.js | 49 ++ .../Specifications/EditSpecificationModal.js | 27 ++ .../EditSpecificationModalConnector.js | 50 ++ .../EditSpecificationModalContent.css | 5 + .../EditSpecificationModalContent.js | 160 +++++++ .../EditSpecificationModalContentConnector.js | 78 ++++ .../Specifications/Specification.css | 38 ++ .../Specifications/Specification.js | 139 ++++++ .../MediaManagement/MediaManagement.js | 2 +- .../MediaManagement/Naming/NamingModal.js | 2 +- .../Delay/EditDelayProfileModalContent.js | 53 ++- .../EditQualityProfileModalContent.css | 17 +- .../Quality/EditQualityProfileModalContent.js | 66 ++- ...EditQualityProfileModalContentConnector.js | 48 +- .../Quality/QualityProfileFormatItem.css | 45 ++ .../Quality/QualityProfileFormatItem.js | 68 +++ .../Quality/QualityProfileFormatItems.css | 31 ++ .../Quality/QualityProfileFormatItems.js | 159 +++++++ .../Release/EditReleaseProfileModalContent.js | 40 +- ...EditReleaseProfileModalContentConnector.js | 5 +- .../Profiles/Release/ReleaseProfile.css | 6 + .../Profiles/Release/ReleaseProfile.js | 48 +- frontend/src/Settings/Settings.js | 11 + .../Settings/customFormatSpecifications.js | 193 ++++++++ .../Store/Actions/Settings/customFormats.js | 108 +++++ .../src/Store/Actions/blocklistActions.js | 6 + frontend/src/Store/Actions/historyActions.js | 24 +- frontend/src/Store/Actions/queueActions.js | 6 + frontend/src/Store/Actions/releaseActions.js | 5 + frontend/src/Store/Actions/settingsActions.js | 10 + .../Number/formatPreferredWordScore.js | 16 + frontend/src/Utilities/State/getNextId.js | 5 + .../src/Utilities/State/getProviderState.js | 17 +- package.json | 1 + .../Blocklist/BlocklistController.cs | 8 +- .../Blocklist/BlocklistResource.cs | 6 +- .../CustomFormats/CustomFormatController.cs | 115 +++++ .../CustomFormats/CustomFormatResource.cs | 75 +++ .../CustomFormatSpecificationSchema.cs | 36 ++ .../History/HistoryController.cs | 6 +- src/Lidarr.Api.V1/History/HistoryResource.cs | 6 +- src/Lidarr.Api.V1/Indexers/ReleaseResource.cs | 7 +- .../Profiles/Delay/DelayProfileResource.cs | 11 +- .../Quality/QualityProfileController.cs | 22 +- .../Quality/QualityProfileResource.cs | 41 +- .../Release/ReleaseProfileController.cs | 7 +- .../Release/ReleaseProfileResource.cs | 10 +- src/Lidarr.Api.V1/Queue/QueueResource.cs | 3 + src/Lidarr.Http/ClientSchema/Field.cs | 1 + src/Lidarr.Http/REST/RestResource.cs | 2 +- .../CustomFormats/CustomFormatsTestHelpers.cs | 32 ++ .../063_add_custom_formatsFixture.cs | 431 ++++++++++++++++++ ...matAllowedByProfileSpecificationFixture.cs | 116 +++++ .../CutoffSpecificationFixture.cs | 34 +- .../PrioritizeDownloadDecisionFixture.cs | 26 +- .../QueueSpecificationFixture.cs | 45 +- ...ReleaseRestrictionsSpecificationFixture.cs | 19 +- .../RssSync/DelaySpecificationFixture.cs | 58 ++- .../HistorySpecificationFixture.cs | 18 +- .../UpgradeAllowedSpecificationFixture.cs | 192 ++++++-- .../UpgradeDiskSpecificationFixture.cs | 23 +- .../UpgradeSpecificationFixture.cs | 15 +- .../PendingReleaseServiceTests/AddFixture.cs | 1 + .../RemovePendingFixture.cs | 4 +- ...CleanupQualityProfileFormatItemsFixture.cs | 134 ++++++ .../TrackImport/GetSceneNameFixture.cs | 143 ++++++ .../SameFileSpecificationFixture.cs | 109 ----- .../FileNameBuilderTests/CleanTitleFixture.cs | 5 + .../FileNameBuilderFixture.cs | 6 +- .../FileNameBuilderTests/TitleTheFixture.cs | 5 + ...ure.cs => QualityProfileServiceFixture.cs} | 8 +- .../PreferredWordService/CalculateFixture.cs | 94 ---- .../GetMatchingPreferredWordsFixture.cs | 77 ---- src/NzbDrone.Core/Annotations/SelectOption.cs | 10 + .../Annotations/SelectOptionsConverter.cs | 9 + .../CustomFormats/CustomFormat.cs | 71 +++ .../CustomFormatCalculationService.cs | 183 ++++++++ .../CustomFormats/CustomFormatInput.cs | 38 ++ .../CustomFormats/CustomFormatRepository.cs | 17 + .../CustomFormats/CustomFormatService.cs | 77 ++++ .../Events/CustomFormatAddedEvent.cs | 14 + .../Events/CustomFormatDeletedEvent.cs | 14 + .../SpecificationMatchesGroup.cs | 13 + .../CustomFormatSpecificationBase.cs | 36 ++ .../ICustomFormatSpecification.cs | 20 + .../Specifications/RegexSpecificationBase.cs | 54 +++ .../ReleaseGroupSpecification.cs | 14 + .../ReleaseTitleSpecification.cs | 14 + .../Specifications/SizeSpecification.cs | 41 ++ .../Converters/CustomFormatIntConverter.cs | 20 + .../CustomFormatSpecificationConverter.cs | 74 +++ .../Migration/063_add_custom_formats.cs | 307 +++++++++++++ src/NzbDrone.Core/Datastore/TableMapping.cs | 6 + .../DownloadDecisionComparer.cs | 6 +- .../DecisionEngine/DownloadDecisionMaker.cs | 93 ++-- ...stomFormatAllowedByProfileSpecification.cs | 25 + .../Specifications/CutoffSpecification.cs | 14 +- .../Specifications/QueueSpecification.cs | 28 +- .../ReleaseRestrictionsSpecification.cs | 8 +- .../RssSync/DelaySpecification.cs | 28 +- .../RssSync/HistorySpecification.cs | 30 +- .../Specifications/UpgradableSpecification.cs | 54 ++- .../UpgradeAllowedSpecification.cs | 15 +- .../UpgradeDiskSpecification.cs | 14 +- .../AggregatePreferredWordScore.cs | 22 - .../History/DownloadHistoryService.cs | 2 +- .../Download/Pending/PendingReleaseService.cs | 11 + .../TrackedDownloadService.cs | 12 +- .../History/EntityHistoryService.cs | 1 + .../CleanupQualityProfileFormatItems.cs | 93 ++++ src/NzbDrone.Core/Localization/Core/en.json | 10 +- .../DownloadedTracksImportService.cs | 21 +- src/NzbDrone.Core/MediaFiles/TrackFile.cs | 3 +- .../Aggregation/AggregationService.cs | 6 +- .../Aggregators/AggregateQuality.cs | 2 +- .../Aggregators/AggregateReleaseGroup.cs | 2 +- .../TrackImport/ImportApprovedTracks.cs | 38 +- .../TrackImport/ImportDecisionMaker.cs | 8 +- .../TrackImport/Manual/ManualImportItem.cs | 3 + .../TrackImport/Manual/ManualImportService.cs | 8 +- .../TrackImport/SceneNameCalculator.cs | 38 ++ .../Specifications/SameFileSpecification.cs | 53 --- .../Specifications/UpgradeSpecification.cs | 7 +- .../Notifications/Webhook/WebhookRelease.cs | 6 + .../Organizer/FileNameBuilder.cs | 22 +- .../Organizer/FileNameSampleService.cs | 24 +- src/NzbDrone.Core/Parser/Model/LocalTrack.cs | 3 +- .../Parser/Model/ParsedAlbumInfo.cs | 6 + src/NzbDrone.Core/Parser/Model/RemoteAlbum.cs | 5 +- .../Profiles/Delay/DelayProfile.cs | 5 +- .../Profiles/ProfileFormatItem.cs | 11 + .../Profiles/Qualities/QualityProfile.cs | 14 + .../Qualities/QualityProfileRepository.cs | 40 +- .../Qualities/QualityProfileService.cs | 55 ++- .../Profiles/Releases/PreferredWordService.cs | 86 ---- .../Profiles/Releases/ReleaseProfile.cs | 10 +- .../Releases/ReleaseProfileService.cs | 8 - .../CaseInsensitiveTermMatcher.cs | 4 +- yarn.lock | 37 +- 187 files changed, 6947 insertions(+), 892 deletions(-) create mode 100644 frontend/src/Album/AlbumFormats.js create mode 100644 frontend/src/Components/Form/TextArea.css create mode 100644 frontend/src/Components/Form/TextArea.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormatSettingsConnector.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/CustomFormat.css create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/CustomFormat.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/CustomFormats.css create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/CustomFormats.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/CustomFormatsConnector.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModal.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalConnector.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalContent.css create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalContent.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalContentConnector.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/ExportCustomFormatModal.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/ExportCustomFormatModalContent.css create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/ExportCustomFormatModalContent.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/ExportCustomFormatModalContentConnector.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/ImportCustomFormatModal.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/ImportCustomFormatModalContent.css create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/ImportCustomFormatModalContent.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/ImportCustomFormatModalContentConnector.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/Specifications/AddSpecificationItem.css create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/Specifications/AddSpecificationItem.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/Specifications/AddSpecificationModal.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/Specifications/AddSpecificationModalContent.css create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/Specifications/AddSpecificationModalContent.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/Specifications/AddSpecificationModalContentConnector.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/Specifications/AddSpecificationPresetMenuItem.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/Specifications/EditSpecificationModal.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/Specifications/EditSpecificationModalConnector.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/Specifications/EditSpecificationModalContent.css create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/Specifications/EditSpecificationModalContent.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/Specifications/EditSpecificationModalContentConnector.js create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/Specifications/Specification.css create mode 100644 frontend/src/Settings/CustomFormats/CustomFormats/Specifications/Specification.js create mode 100644 frontend/src/Settings/Profiles/Quality/QualityProfileFormatItem.css create mode 100644 frontend/src/Settings/Profiles/Quality/QualityProfileFormatItem.js create mode 100644 frontend/src/Settings/Profiles/Quality/QualityProfileFormatItems.css create mode 100644 frontend/src/Settings/Profiles/Quality/QualityProfileFormatItems.js create mode 100644 frontend/src/Store/Actions/Settings/customFormatSpecifications.js create mode 100644 frontend/src/Store/Actions/Settings/customFormats.js create mode 100644 frontend/src/Utilities/Number/formatPreferredWordScore.js create mode 100644 frontend/src/Utilities/State/getNextId.js create mode 100644 src/Lidarr.Api.V1/CustomFormats/CustomFormatController.cs create mode 100644 src/Lidarr.Api.V1/CustomFormats/CustomFormatResource.cs create mode 100644 src/Lidarr.Api.V1/CustomFormats/CustomFormatSpecificationSchema.cs create mode 100644 src/NzbDrone.Core.Test/CustomFormats/CustomFormatsTestHelpers.cs create mode 100644 src/NzbDrone.Core.Test/Datastore/Migration/063_add_custom_formatsFixture.cs create mode 100644 src/NzbDrone.Core.Test/DecisionEngineTests/CustomFormatAllowedByProfileSpecificationFixture.cs rename src/NzbDrone.Core.Test/DecisionEngineTests/{ => RssSync}/HistorySpecificationFixture.cs (93%) create mode 100644 src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupQualityProfileFormatItemsFixture.cs create mode 100644 src/NzbDrone.Core.Test/MediaFiles/TrackImport/GetSceneNameFixture.cs delete mode 100644 src/NzbDrone.Core.Test/MediaFiles/TrackImport/Specifications/SameFileSpecificationFixture.cs rename src/NzbDrone.Core.Test/Profiles/{ProfileServiceFixture.cs => QualityProfileServiceFixture.cs} (95%) delete mode 100644 src/NzbDrone.Core.Test/Profiles/Releases/PreferredWordService/CalculateFixture.cs delete mode 100644 src/NzbDrone.Core.Test/Profiles/Releases/PreferredWordService/GetMatchingPreferredWordsFixture.cs create mode 100644 src/NzbDrone.Core/Annotations/SelectOption.cs create mode 100644 src/NzbDrone.Core/Annotations/SelectOptionsConverter.cs create mode 100644 src/NzbDrone.Core/CustomFormats/CustomFormat.cs create mode 100644 src/NzbDrone.Core/CustomFormats/CustomFormatCalculationService.cs create mode 100644 src/NzbDrone.Core/CustomFormats/CustomFormatInput.cs create mode 100644 src/NzbDrone.Core/CustomFormats/CustomFormatRepository.cs create mode 100644 src/NzbDrone.Core/CustomFormats/CustomFormatService.cs create mode 100644 src/NzbDrone.Core/CustomFormats/Events/CustomFormatAddedEvent.cs create mode 100644 src/NzbDrone.Core/CustomFormats/Events/CustomFormatDeletedEvent.cs create mode 100644 src/NzbDrone.Core/CustomFormats/SpecificationMatchesGroup.cs create mode 100644 src/NzbDrone.Core/CustomFormats/Specifications/CustomFormatSpecificationBase.cs create mode 100644 src/NzbDrone.Core/CustomFormats/Specifications/ICustomFormatSpecification.cs create mode 100644 src/NzbDrone.Core/CustomFormats/Specifications/RegexSpecificationBase.cs create mode 100644 src/NzbDrone.Core/CustomFormats/Specifications/ReleaseGroupSpecification.cs create mode 100644 src/NzbDrone.Core/CustomFormats/Specifications/ReleaseTitleSpecification.cs create mode 100644 src/NzbDrone.Core/CustomFormats/Specifications/SizeSpecification.cs create mode 100644 src/NzbDrone.Core/Datastore/Converters/CustomFormatIntConverter.cs create mode 100644 src/NzbDrone.Core/Datastore/Converters/CustomFormatSpecificationConverter.cs create mode 100644 src/NzbDrone.Core/Datastore/Migration/063_add_custom_formats.cs create mode 100644 src/NzbDrone.Core/DecisionEngine/Specifications/CustomFormatAllowedByProfileSpecification.cs delete mode 100644 src/NzbDrone.Core/Download/Aggregation/Aggregators/AggregatePreferredWordScore.cs create mode 100644 src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupQualityProfileFormatItems.cs create mode 100644 src/NzbDrone.Core/MediaFiles/TrackImport/SceneNameCalculator.cs delete mode 100644 src/NzbDrone.Core/MediaFiles/TrackImport/Specifications/SameFileSpecification.cs create mode 100644 src/NzbDrone.Core/Profiles/ProfileFormatItem.cs delete mode 100644 src/NzbDrone.Core/Profiles/Releases/PreferredWordService.cs diff --git a/frontend/build/webpack.config.js b/frontend/build/webpack.config.js index 6f324ac95..1c86e39d4 100644 --- a/frontend/build/webpack.config.js +++ b/frontend/build/webpack.config.js @@ -44,7 +44,8 @@ module.exports = (env) => { 'node_modules' ], alias: { - jquery: 'jquery/src/jquery' + jquery: 'jquery/src/jquery', + 'react-middle-truncate': 'react-middle-truncate/lib/react-middle-truncate' }, fallback: { buffer: false, diff --git a/frontend/src/Activity/Blocklist/BlocklistRow.js b/frontend/src/Activity/Blocklist/BlocklistRow.js index 3fc813196..9dcfc47cd 100644 --- a/frontend/src/Activity/Blocklist/BlocklistRow.js +++ b/frontend/src/Activity/Blocklist/BlocklistRow.js @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; +import AlbumFormats from 'Album/AlbumFormats'; import TrackQuality from 'Album/TrackQuality'; import ArtistNameLink from 'Artist/ArtistNameLink'; import IconButton from 'Components/Link/IconButton'; @@ -45,6 +46,7 @@ class BlocklistRow extends Component { artist, sourceTitle, quality, + customFormats, date, protocol, indexer, @@ -110,6 +112,16 @@ class BlocklistRow extends Component { ); } + if (name === 'customFormats') { + return ( + + + + ); + } + if (name === 'date') { return ( : + null + } + + { + nzbInfoUrl ? Info URL @@ -114,7 +125,8 @@ function HistoryDetails(props) { {nzbInfoUrl} - + : + null } { @@ -179,6 +191,7 @@ function HistoryDetails(props) { if (eventType === 'trackFileImported') { const { + customFormatScore, droppedPath, importedPath } = data; @@ -201,12 +214,22 @@ function HistoryDetails(props) { } { - !!importedPath && + importedPath ? + /> : + null + } + + { + customFormatScore && customFormatScore !== '0' ? + : + null } ); @@ -214,7 +237,8 @@ function HistoryDetails(props) { if (eventType === 'trackFileDeleted') { const { - reason + reason, + customFormatScore } = data; let reasonMessage = ''; @@ -244,6 +268,15 @@ function HistoryDetails(props) { title={translate('Reason')} data={reasonMessage} /> + + { + customFormatScore && customFormatScore !== '0' ? + : + null + } ); } diff --git a/frontend/src/Activity/History/HistoryRow.css b/frontend/src/Activity/History/HistoryRow.css index 669377fdb..039804b63 100644 --- a/frontend/src/Activity/History/HistoryRow.css +++ b/frontend/src/Activity/History/HistoryRow.css @@ -10,6 +10,12 @@ width: 80px; } +.customFormatScore { + composes: cell from '~Components/Table/Cells/TableRowCell.css'; + + width: 55px; +} + .releaseGroup { composes: cell from '~Components/Table/Cells/TableRowCell.css'; diff --git a/frontend/src/Activity/History/HistoryRow.js b/frontend/src/Activity/History/HistoryRow.js index 98718f70f..9bac266f4 100644 --- a/frontend/src/Activity/History/HistoryRow.js +++ b/frontend/src/Activity/History/HistoryRow.js @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; +import AlbumFormats from 'Album/AlbumFormats'; import AlbumTitleLink from 'Album/AlbumTitleLink'; import TrackQuality from 'Album/TrackQuality'; import ArtistNameLink from 'Artist/ArtistNameLink'; @@ -8,6 +9,7 @@ import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellCo import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableRow from 'Components/Table/TableRow'; import { icons } from 'Helpers/Props'; +import formatPreferredWordScore from 'Utilities/Number/formatPreferredWordScore'; import HistoryDetailsModal from './Details/HistoryDetailsModal'; import HistoryEventTypeCell from './HistoryEventTypeCell'; import styles from './HistoryRow.css'; @@ -55,6 +57,7 @@ class HistoryRow extends Component { album, track, quality, + customFormats, qualityCutoffNotMet, eventType, sourceTitle, @@ -136,6 +139,16 @@ class HistoryRow extends Component { ); } + if (name === 'customFormats') { + return ( + + + + ); + } + if (name === 'date') { return ( + {formatPreferredWordScore(data.customFormatScore)} + + ); + } + if (name === 'releaseGroup') { return ( + + + ); + } + if (name === 'protocol') { return ( @@ -382,6 +394,7 @@ QueueRow.propTypes = { artist: PropTypes.object, album: PropTypes.object, quality: PropTypes.object.isRequired, + customFormats: PropTypes.arrayOf(PropTypes.object), protocol: PropTypes.string.isRequired, indexer: PropTypes.string, outputPath: PropTypes.string, diff --git a/frontend/src/Album/AlbumFormats.js b/frontend/src/Album/AlbumFormats.js new file mode 100644 index 000000000..1591fa714 --- /dev/null +++ b/frontend/src/Album/AlbumFormats.js @@ -0,0 +1,33 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import Label from 'Components/Label'; +import { kinds } from 'Helpers/Props'; + +function AlbumFormats({ formats }) { + return ( +
+ { + formats.map((format) => { + return ( + + ); + }) + } +
+ ); +} + +AlbumFormats.propTypes = { + formats: PropTypes.arrayOf(PropTypes.object).isRequired +}; + +AlbumFormats.defaultProps = { + formats: [] +}; + +export default AlbumFormats; diff --git a/frontend/src/App/AppRoutes.js b/frontend/src/App/AppRoutes.js index 0285559a8..223e0f90e 100644 --- a/frontend/src/App/AppRoutes.js +++ b/frontend/src/App/AppRoutes.js @@ -13,6 +13,7 @@ import CalendarPageConnector from 'Calendar/CalendarPageConnector'; import NotFound from 'Components/NotFound'; import Switch from 'Components/Router/Switch'; import AddNewItemConnector from 'Search/AddNewItemConnector'; +import CustomFormatSettingsConnector from 'Settings/CustomFormats/CustomFormatSettingsConnector'; import DownloadClientSettingsConnector from 'Settings/DownloadClients/DownloadClientSettingsConnector'; import GeneralSettingsConnector from 'Settings/General/GeneralSettingsConnector'; import ImportListSettingsConnector from 'Settings/ImportLists/ImportListSettingsConnector'; @@ -167,6 +168,11 @@ function AppRoutes(props) { component={QualityConnector} /> + + { + this._input = ref; + }; + + selectionChange() { + if (this._selectionTimeout) { + this._selectionTimeout = clearTimeout(this._selectionTimeout); + } + + this._selectionTimeout = setTimeout(() => { + const selectionStart = this._input.selectionStart; + const selectionEnd = this._input.selectionEnd; + + const selectionChanged = ( + this._selectionStart !== selectionStart || + this._selectionEnd !== selectionEnd + ); + + this._selectionStart = selectionStart; + this._selectionEnd = selectionEnd; + + if (this.props.onSelectionChange && selectionChanged) { + this.props.onSelectionChange(selectionStart, selectionEnd); + } + }, 10); + } + + // + // Listeners + + onChange = (event) => { + const { + name, + onChange + } = this.props; + + const payload = { + name, + value: event.target.value + }; + + onChange(payload); + }; + + onFocus = (event) => { + if (this.props.onFocus) { + this.props.onFocus(event); + } + + this.selectionChange(); + }; + + onKeyUp = () => { + this.selectionChange(); + }; + + onMouseDown = () => { + this._isMouseTarget = true; + }; + + onMouseUp = () => { + this.selectionChange(); + }; + + onDocumentMouseUp = () => { + if (this._isMouseTarget) { + this.selectionChange(); + } + + this._isMouseTarget = false; + }; + + // + // Render + + render() { + const { + className, + readOnly, + autoFocus, + placeholder, + name, + value, + hasError, + hasWarning, + onBlur + } = this.props; + + return ( +