From 361ffe353d780406458a64517933439862434524 Mon Sep 17 00:00:00 2001 From: Qstick Date: Thu, 3 Sep 2020 22:50:56 -0400 Subject: [PATCH] New: Browse Lists from Discover Movies Page --- .../AddNewMovie/AddNewMovieConnector.js | 8 +- .../AddNewMovie/AddNewMovieSearchResult.js | 2 +- frontend/src/App/AppRoutes.js | 6 +- frontend/src/Commands/commandNames.js | 1 + .../Filter/Builder/FilterBuilderRow.js | 4 + ...mportListFilterBuilderRowValueConnector.js | 27 ++ frontend/src/Components/ImportListList.css | 3 + frontend/src/Components/ImportListList.js | 43 +++ .../src/Components/ImportListListConnector.js | 17 ++ frontend/src/Components/Page/PageConnector.js | 26 +- .../Components/Page/Sidebar/PageSidebar.js | 2 +- frontend/src/DiscoverMovie/DiscoverMovie.js | 50 ++-- .../DiscoverMovie/DiscoverMovieConnector.js | 33 ++- ...s => DiscoverMovieFilterModalConnector.js} | 0 .../src/DiscoverMovie/DiscoverMovieFooter.css | 2 +- .../DiscoverMovieFooterConnector.js | 6 +- ...ector.js => DiscoverMovieItemConnector.js} | 6 +- .../ExcludeMovieModalContentConnector.js | 8 +- ...lterMenu.js => DiscoverMovieFilterMenu.js} | 12 +- ...ieSortMenu.js => DiscoverMovieSortMenu.js} | 24 +- ...ieViewMenu.js => DiscoverMovieViewMenu.js} | 6 +- frontend/src/DiscoverMovie/NoDiscoverMovie.js | 2 +- ...Overview.css => DiscoverMovieOverview.css} | 14 +- ...ieOverview.js => DiscoverMovieOverview.js} | 74 ++++- ...r.js => DiscoverMovieOverviewConnector.js} | 4 +- .../Overview/DiscoverMovieOverviewInfo.css | 12 + .../Overview/DiscoverMovieOverviewInfo.js | 147 +++++++++ .../Overview/DiscoverMovieOverviewInfoRow.css | 10 + .../Overview/DiscoverMovieOverviewInfoRow.js | 35 +++ ...erviews.css => DiscoverMovieOverviews.css} | 0 ...Overviews.js => DiscoverMovieOverviews.js} | 16 +- ....js => DiscoverMovieOverviewsConnector.js} | 4 +- ...AddListMovieOverviewOptionsModalContent.js | 133 --------- ...s => DiscoverMovieOverviewOptionsModal.js} | 10 +- ...iscoverMovieOverviewOptionsModalContent.js | 239 +++++++++++++++ ...ieOverviewOptionsModalContentConnector.js} | 14 +- .../Posters/AddListMoviePosterInfo.js | 30 -- ...oviePoster.css => DiscoverMoviePoster.css} | 0 ...tMoviePoster.js => DiscoverMoviePoster.js} | 26 +- ...tor.js => DiscoverMoviePosterConnector.js} | 4 +- ...erInfo.css => DiscoverMoviePosterInfo.css} | 0 .../Posters/DiscoverMoviePosterInfo.js | 139 +++++++++ ...iePosters.css => DiscoverMoviePosters.css} | 0 ...oviePosters.js => DiscoverMoviePosters.js} | 16 +- ...or.js => DiscoverMoviePostersConnector.js} | 4 +- ....js => DiscoverMoviePosterOptionsModal.js} | 10 +- ...DiscoverMoviePosterOptionsModalContent.js} | 43 ++- ...oviePosterOptionsModalContentConnector.js} | 14 +- ...onsCell.js => DiscoverMovieActionsCell.js} | 6 +- ...ovieHeader.css => DiscoverMovieHeader.css} | 24 +- ...tMovieHeader.js => DiscoverMovieHeader.js} | 28 +- ...tor.js => DiscoverMovieHeaderConnector.js} | 4 +- ...dListMovieRow.css => DiscoverMovieRow.css} | 33 ++- ...AddListMovieRow.js => DiscoverMovieRow.js} | 112 ++++++- ...nector.js => DiscoverMovieRowConnector.js} | 4 +- ...tMovieTable.css => DiscoverMovieTable.css} | 0 ...istMovieTable.js => DiscoverMovieTable.js} | 20 +- ...ctor.js => DiscoverMovieTableConnector.js} | 4 +- .../Table/DiscoverMovieTableOptions.js | 73 +++++ .../DiscoverMovieTableOptionsConnector.js | 24 ++ .../Table/ListMovieStatusCell.css | 10 - .../Table/ListMovieStatusCell.js | 12 - .../Helpers/Props/filterBuilderValueTypes.js | 1 + frontend/src/Helpers/Props/icons.js | 8 +- .../Movie/Delete/DeleteMovieModalContent.js | 20 +- .../DeleteMovieModalContentConnector.js | 4 +- .../Details/Credits/Cast/MovieCastPoster.js | 42 +-- .../Details/Credits/Crew/MovieCrewPoster.js | 42 +-- .../Credits/MovieCreditPosterConnector.js | 24 +- .../Movie/Details/MovieDetailsConnector.js | 10 +- .../Editor/Delete/DeleteMovieModalContent.js | 22 +- .../DeleteMovieModalContentConnector.js | 4 +- frontend/src/Movie/MovieCollection.js | 26 +- .../src/Movie/MovieCollectionConnector.js | 46 +-- .../EditImportExclusionModal.js} | 10 +- .../EditImportExclusionModalConnector.js} | 12 +- .../EditImportExclusionModalContent.css} | 0 .../EditImportExclusionModalContent.js} | 14 +- ...itImportExclusionModalContentConnector.js} | 48 +-- .../ImportExclusions/ImportExclusion.css} | 2 +- .../ImportExclusions/ImportExclusion.js} | 58 ++-- .../ImportExclusions/ImportExclusions.css} | 4 +- .../ImportExclusions/ImportExclusions.js} | 38 +-- .../ImportExclusionsConnector.js | 59 ++++ .../ImportListSettings.js} | 24 +- .../ImportListSettingsConnector.js} | 10 +- .../ImportLists/AddImportListItem.css} | 2 +- .../ImportLists/AddImportListItem.js} | 28 +- .../ImportLists/AddImportListModal.js} | 10 +- .../AddImportListModalContent.css} | 2 +- .../ImportLists/AddImportListModalContent.js} | 30 +- .../AddImportListModalContentConnector.js} | 36 +-- .../AddImportListPresetMenuItem.js} | 6 +- .../ImportLists/EditImportListModal.js} | 10 +- .../EditImportListModalConnector.js | 65 ++++ .../EditImportListModalContent.css} | 0 .../EditImportListModalContent.js} | 32 +- .../EditImportListModalContentConnector.js} | 42 +-- .../ImportLists/ImportList.css} | 2 +- .../ImportLists/ImportList.js} | 56 ++-- .../ImportLists/ImportLists.css} | 6 +- .../ImportLists/ImportLists.js} | 62 ++-- .../ImportLists/ImportListsConnector.js} | 32 +- .../Options/ImportListOptions.js} | 12 +- .../Options/ImportListOptionsConnector.js} | 36 +-- .../NetImport/EditNetImportModalConnector.js | 65 ---- .../NetImportExclusionsConnector.js | 59 ---- frontend/src/Settings/Settings.js | 2 +- .../Tags/Details/TagDetailsModalContent.js | 8 +- .../TagDetailsModalContentConnector.js | 12 +- frontend/src/Settings/Tags/Tag.js | 14 +- frontend/src/Settings/Tags/TagsConnector.js | 10 +- .../Actions/Settings/importExclusions.js | 71 +++++ .../Actions/Settings/importListOptions.js | 64 ++++ .../src/Store/Actions/Settings/importLists.js | 116 ++++++++ .../Actions/Settings/netImportExclusions.js | 71 ----- .../Actions/Settings/netImportOptions.js | 64 ---- .../src/Store/Actions/Settings/netImports.js | 116 -------- .../src/Store/Actions/discoverMovieActions.js | 121 +++++++- frontend/src/Store/Actions/settingsActions.js | 30 +- .../Selectors/createExclusionMovieSelector.js | 6 +- .../Selectors/createImportListSelector.js | 12 + .../createMovieCollectionListSelector.js | 10 +- .../createMovieCreditListSelector.js | 14 +- .../Selectors/createProfileInUseSelector.js | 2 +- .../Config/NetImportConfigModule.cs | 12 +- .../Config/NetImportConfigResource.cs | 12 +- .../Movies/FetchMovieListModule.cs | 58 ---- .../Movies/MovieBulkImportModule.cs | 187 ------------ .../Movies/MovieDiscoverModule.cs | 14 +- .../NetImport/ImportExclusionsModule.cs | 8 +- .../NetImport/ImportExclusionsResource.cs | 10 +- .../NetImport/ListImportModule.cs | 34 --- src/NzbDrone.Api/NetImport/NetImportModule.cs | 16 +- .../NetImport/NetImportResource.cs | 4 +- src/NzbDrone.Api/swagger.json | 2 +- .../Cloud/RadarrCloudRequestBuilder.cs | 6 - .../Extensions/IEnumerableExtensions.cs | 5 + .../Migration/178_new_list_serverFixture.cs | 8 +- .../Checks/NetImportStatusCheckFixture.cs | 20 +- .../CouchPotato/CouchPotatoParserFixture.cs | 10 +- .../FetchAndParseImportListServiceFixture.cs | 189 ++++++++++++ .../ImportListStatusServiceFixture.cs} | 24 +- .../ImportListSyncServiceFixture.cs} | 280 +++++++++--------- .../RSSImportFixture.cs | 4 +- .../RSSImportParserFixture.cs | 10 +- .../Messaging/Commands/CommandQueueFixture.cs | 191 ++++++++++++ .../Profiles/ProfileServiceFixture.cs | 14 +- .../ThingiProvider/ProviderBaseFixture.cs | 29 -- .../Configuration/ConfigService.cs | 6 +- .../Configuration/IConfigService.cs | 2 +- .../Migration/181_list_movies_table.cs | 44 +++ src/NzbDrone.Core/Datastore/TableMapping.cs | 15 +- ...tatusCheck.cs => ImportListStatusCheck.cs} | 20 +- .../Housekeepers/CleanupUnusedTags.cs | 2 +- .../CleanLibraryLevel.cs} | 4 +- .../CouchPotato/CouchPotatoAPI.cs | 2 +- .../CouchPotato/CouchPotatoImport.cs | 31 ++ .../CouchPotato/CouchPotatoParser.cs | 44 ++- .../CouchPotatoRequestGenerator.cs | 12 +- .../CouchPotato/CouchPotatoSettings.cs | 2 +- .../Exceptions/ImportListException.cs | 21 ++ .../FetchAndParseImportListService.cs | 207 +++++++++++++ .../HttpImportListBase.cs} | 72 ++--- src/NzbDrone.Core/ImportLists/IImportList.cs | 13 + .../IImportListRequestGenerator.cs | 7 + .../ImportLists/IParseImportListResponse.cs | 10 + .../ImportExclusions/ImportExclusion.cs | 2 +- .../ImportExclusionsRepository.cs | 2 +- .../ImportExclusionsService.cs | 10 +- .../ImportListBase.cs} | 40 ++- .../ImportListBaseSettings.cs} | 12 +- .../ImportListDefinition.cs} | 11 +- .../ImportLists/ImportListFactory.cs | 56 ++++ .../ImportListMovies/ImportListMovie.cs | 45 +++ .../ImportListMovieRepository.cs | 24 ++ .../ImportListMovieService.cs | 105 +++++++ .../ImportLists/ImportListPageableRequest.cs | 25 ++ .../ImportListPageableRequestChain.cs | 54 ++++ .../ImportLists/ImportListRepository.cs | 24 ++ .../ImportListRequest.cs} | 8 +- .../ImportListResponse.cs} | 12 +- .../ImportListStatus.cs} | 4 +- .../ImportLists/ImportListStatusRepository.cs | 18 ++ .../ImportListStatusService.cs} | 8 +- .../ImportLists/ImportListSyncCommand.cs | 24 ++ .../ImportLists/ImportListSyncService.cs | 217 ++++++++++++++ .../ImportListType.cs} | 4 +- .../ImportLists/ImportListUpdatedHandler.cs | 26 ++ .../RSSImport/RSSImport.cs | 18 +- .../RSSImport/RSSImportParser.cs | 40 +-- .../RSSImport/RSSImportRequestGenerator.cs | 29 ++ .../RSSImport/RSSImportSettings.cs | 2 +- .../Radarr/RadarrAPIResource.cs | 2 +- .../Radarr/RadarrImport.cs | 32 +- .../Radarr/RadarrSettings.cs | 2 +- .../Radarr/RadarrV3Proxy.cs | 2 +- .../RadarrList/RadarrListException.cs | 2 +- .../RadarrList/RadarrListImport.cs | 14 +- .../RadarrList/RadarrListParser.cs | 24 +- .../RadarrList/RadarrListRequestGenerator.cs | 25 ++ .../RadarrList/RadarrListSettings.cs | 2 +- .../RadarrList2/IMDb/IMDbListImport.cs | 18 +- .../IMDb/IMDbListRequestGenerator.cs | 2 +- .../RadarrList2/IMDb/IMDbListSettings.cs | 2 +- .../RadarrList2/RadarrList2Parser.cs | 22 +- .../RadarrList2RequestGenerator.cs | 12 +- .../RadarrList2/StevenLu/StevenLu2Import.cs | 14 +- .../StevenLu/StevenLu2RequestGenerator.cs | 2 +- .../RadarrList2/StevenLu/StevenLu2Settings.cs | 2 +- .../StevenLu/StevenLuAPI.cs | 2 +- .../StevenLu/StevenLuImport.cs | 14 +- .../ImportLists/StevenLu/StevenLuParser.cs | 65 ++++ .../StevenLu/StevenLuRequestGenerator.cs | 23 ++ .../StevenLu/StevenLuSettings.cs | 2 +- .../TMDb/Collection/TMDbCollectionImport.cs | 12 +- .../TMDb/Collection/TMDbCollectionParser.cs | 8 +- .../TMDbCollectionRequestGenerator.cs | 12 +- .../TMDb/Collection/TMDbCollectionSettings.cs | 2 +- .../TMDb/List/TMDbListImport.cs | 12 +- .../TMDb/List/TMDbListParser.cs | 8 +- .../TMDb/List/TMDbListRequestGenerator.cs | 12 +- .../TMDb/List/TMDbListSettings.cs | 2 +- .../TMDb/Person/TMDbPersonImport.cs | 12 +- .../TMDb/Person/TMDbPersonParser.cs | 12 +- .../TMDb/Person/TMDbPersonRequestGenerator.cs | 12 +- .../TMDb/Person/TMDbPersonSettings.cs | 2 +- .../TMDb/Popular/TMDbPopularImport.cs | 12 +- .../TMDb/Popular/TMDbPopularListType.cs | 2 +- .../Popular/TMDbPopularRequestGenerator.cs | 12 +- .../TMDb/Popular/TMDbPopularSettings.cs | 2 +- .../TMDb/TMDBResources.cs | 2 +- .../TMDb/TMDbFilterSettings.cs | 2 +- .../TMDb/TMDbImportBase.cs | 12 +- .../TMDb/TMDbLanguageCodes.cs | 2 +- .../TMDb/TMDbParser.cs | 28 +- .../TMDb/TMDbSettings.cs | 2 +- .../TMDb/User/TMDbUserImport.cs | 12 +- .../TMDb/User/TMDbUserListType.cs | 2 +- .../TMDb/User/TMDbUserRequestGenerator.cs | 12 +- .../TMDb/User/TMDbUserSettings.cs | 2 +- .../Trakt/List/TraktListImport.cs | 10 +- .../Trakt/List/TraktListRequestGenerator.cs | 12 +- .../Trakt/List/TraktListSettings.cs | 2 +- .../Trakt/Popular/TraktPopularImport.cs | 12 +- .../Trakt/Popular/TraktPopularListType.cs | 2 +- .../Trakt/Popular/TraktPopularParser.cs | 12 +- .../Popular/TraktPopularRequestGenerator.cs | 12 +- .../Trakt/Popular/TraktPopularSettings.cs | 2 +- .../Trakt/TraktImportBase.cs | 32 +- .../ImportLists/Trakt/TraktParser.cs | 68 +++++ .../Trakt/TraktSettingsBase.cs | 2 +- .../Trakt/User/TraktUserImport.cs | 10 +- .../Trakt/User/TraktUserListType.cs | 2 +- .../Trakt/User/TraktUserRequestGenerator.cs | 12 +- .../Trakt/User/TraktUserSettings.cs | 2 +- src/NzbDrone.Core/Jobs/TaskManager.cs | 16 +- src/NzbDrone.Core/Localization/Core/de.json | 10 +- src/NzbDrone.Core/Localization/Core/en.json | 10 +- src/NzbDrone.Core/Localization/Core/es.json | 6 +- src/NzbDrone.Core/Localization/Core/fr.json | 4 +- src/NzbDrone.Core/Localization/Core/it.json | 4 +- src/NzbDrone.Core/Localization/Core/nl.json | 10 +- src/NzbDrone.Core/Localization/Core/ro.json | 4 +- src/NzbDrone.Core/Localization/Core/sv.json | 4 +- src/NzbDrone.Core/Localization/Core/tr.json | 4 +- .../Messaging/Commands/Command.cs | 1 + .../Messaging/Commands/CommandQueue.cs | 35 ++- .../MetadataSource/SkyHook/SkyHookProxy.cs | 12 +- src/NzbDrone.Core/Movies/MovieRepository.cs | 27 ++ src/NzbDrone.Core/Movies/MovieService.cs | 29 +- .../CouchPotato/CouchPotatoImport.cs | 31 -- .../Exceptions/NetImportException.cs | 23 -- src/NzbDrone.Core/NetImport/INetImport.cs | 13 - .../NetImport/INetImportRequestGenerator.cs | 7 - .../NetImport/IProcessNetImportResponse.cs | 10 - .../NetImport/NetImportFactory.cs | 67 ----- .../NetImport/NetImportPageableRequest.cs | 25 -- .../NetImportPageableRequestChain.cs | 54 ---- .../NetImport/NetImportRepository.cs | 24 -- .../NetImport/NetImportSearchService.cs | 205 ------------- .../NetImport/NetImportStatusRepository.cs | 18 -- .../NetImport/NetImportSyncCommand.cs | 11 - .../RSSImport/RSSImportRequestGenerator.cs | 29 -- .../RadarrList/RadarrListRequestGenerator.cs | 25 -- .../NetImport/StevenLu/StevenLuParser.cs | 64 ---- .../StevenLu/StevenLuRequestGenerator.cs | 23 -- .../NetImport/Trakt/TraktParser.cs | 67 ----- src/NzbDrone.Core/Profiles/ProfileService.cs | 10 +- src/NzbDrone.Core/Tags/TagDetails.cs | 2 +- src/NzbDrone.Core/Tags/TagService.cs | 16 +- .../Config/NetImportConfigModule.cs | 12 +- .../Config/NetImportConfigResource.cs | 12 +- .../ImportExclusionsModule.cs | 26 +- .../ImportExclusionsResource.cs | 5 +- .../ImportListModule.cs} | 14 +- .../ImportLists/ImportListMoviesModule.cs | 117 ++++++++ .../ImportListMoviesResource.cs} | 61 +++- .../ImportListResource.cs} | 17 +- .../Movies/DiscoverMoviesModule.cs | 64 ---- .../Movies/FetchMovieListModule.cs | 73 ----- src/Radarr.Api.V3/Movies/MovieEditorModule.cs | 2 +- .../Movies/MovieEditorResource.cs | 2 +- src/Radarr.Api.V3/Movies/MovieModule.cs | 2 +- src/Radarr.Api.V3/Tags/TagDetailsResource.cs | 4 +- src/Radarr.Api.V3/swagger.json | 2 +- .../NetImportSyncIntervalValidator.cs | 4 +- .../Validation/RuleBuilderExtensions.cs | 4 +- 308 files changed, 4824 insertions(+), 3169 deletions(-) create mode 100644 frontend/src/Components/Filter/Builder/ImportListFilterBuilderRowValueConnector.js create mode 100644 frontend/src/Components/ImportListList.css create mode 100644 frontend/src/Components/ImportListList.js create mode 100644 frontend/src/Components/ImportListListConnector.js rename frontend/src/DiscoverMovie/{AddListMovieFilterModalConnector.js => DiscoverMovieFilterModalConnector.js} (100%) rename frontend/src/DiscoverMovie/{AddListMovieItemConnector.js => DiscoverMovieItemConnector.js} (87%) rename frontend/src/DiscoverMovie/Menus/{AddListMovieFilterMenu.js => DiscoverMovieFilterMenu.js} (72%) rename frontend/src/DiscoverMovie/Menus/{AddListMovieSortMenu.js => DiscoverMovieSortMenu.js} (80%) rename frontend/src/DiscoverMovie/Menus/{AddListMovieViewMenu.js => DiscoverMovieViewMenu.js} (90%) rename frontend/src/DiscoverMovie/Overview/{AddListMovieOverview.css => DiscoverMovieOverview.css} (86%) rename frontend/src/DiscoverMovie/Overview/{AddListMovieOverview.js => DiscoverMovieOverview.js} (77%) rename frontend/src/DiscoverMovie/Overview/{AddListMovieOverviewConnector.js => DiscoverMovieOverviewConnector.js} (73%) create mode 100644 frontend/src/DiscoverMovie/Overview/DiscoverMovieOverviewInfo.css create mode 100644 frontend/src/DiscoverMovie/Overview/DiscoverMovieOverviewInfo.js create mode 100644 frontend/src/DiscoverMovie/Overview/DiscoverMovieOverviewInfoRow.css create mode 100644 frontend/src/DiscoverMovie/Overview/DiscoverMovieOverviewInfoRow.js rename frontend/src/DiscoverMovie/Overview/{AddListMovieOverviews.css => DiscoverMovieOverviews.css} (100%) rename frontend/src/DiscoverMovie/Overview/{AddListMovieOverviews.js => DiscoverMovieOverviews.js} (93%) rename frontend/src/DiscoverMovie/Overview/{AddListMovieOverviewsConnector.js => DiscoverMovieOverviewsConnector.js} (85%) delete mode 100644 frontend/src/DiscoverMovie/Overview/Options/AddListMovieOverviewOptionsModalContent.js rename frontend/src/DiscoverMovie/Overview/Options/{AddListMovieOverviewOptionsModal.js => DiscoverMovieOverviewOptionsModal.js} (50%) create mode 100644 frontend/src/DiscoverMovie/Overview/Options/DiscoverMovieOverviewOptionsModalContent.js rename frontend/src/DiscoverMovie/Overview/Options/{AddListMovieOverviewOptionsModalContentConnector.js => DiscoverMovieOverviewOptionsModalContentConnector.js} (51%) delete mode 100644 frontend/src/DiscoverMovie/Posters/AddListMoviePosterInfo.js rename frontend/src/DiscoverMovie/Posters/{AddListMoviePoster.css => DiscoverMoviePoster.css} (100%) rename frontend/src/DiscoverMovie/Posters/{AddListMoviePoster.js => DiscoverMoviePoster.js} (90%) rename frontend/src/DiscoverMovie/Posters/{AddListMoviePosterConnector.js => DiscoverMoviePosterConnector.js} (74%) rename frontend/src/DiscoverMovie/Posters/{AddListMoviePosterInfo.css => DiscoverMoviePosterInfo.css} (100%) create mode 100644 frontend/src/DiscoverMovie/Posters/DiscoverMoviePosterInfo.js rename frontend/src/DiscoverMovie/Posters/{AddListMoviePosters.css => DiscoverMoviePosters.css} (100%) rename frontend/src/DiscoverMovie/Posters/{AddListMoviePosters.js => DiscoverMoviePosters.js} (94%) rename frontend/src/DiscoverMovie/Posters/{AddListMoviePostersConnector.js => DiscoverMoviePostersConnector.js} (85%) rename frontend/src/DiscoverMovie/Posters/Options/{AddListMoviePosterOptionsModal.js => DiscoverMoviePosterOptionsModal.js} (51%) rename frontend/src/DiscoverMovie/Posters/Options/{AddListMoviePosterOptionsModalContent.js => DiscoverMoviePosterOptionsModalContent.js} (70%) rename frontend/src/DiscoverMovie/Posters/Options/{AddListMoviePosterOptionsModalContentConnector.js => DiscoverMoviePosterOptionsModalContentConnector.js} (51%) rename frontend/src/DiscoverMovie/Table/{AddListMovieActionsCell.js => DiscoverMovieActionsCell.js} (89%) rename frontend/src/DiscoverMovie/Table/{AddListMovieHeader.css => DiscoverMovieHeader.css} (68%) rename frontend/src/DiscoverMovie/Table/{AddListMovieHeader.js => DiscoverMovieHeader.js} (77%) rename frontend/src/DiscoverMovie/Table/{AddListMovieHeaderConnector.js => DiscoverMovieHeaderConnector.js} (66%) rename frontend/src/DiscoverMovie/Table/{AddListMovieRow.css => DiscoverMovieRow.css} (63%) rename frontend/src/DiscoverMovie/Table/{AddListMovieRow.js => DiscoverMovieRow.js} (70%) rename frontend/src/DiscoverMovie/Table/{AddListMovieRowConnector.js => DiscoverMovieRowConnector.js} (75%) rename frontend/src/DiscoverMovie/Table/{AddListMovieTable.css => DiscoverMovieTable.css} (100%) rename frontend/src/DiscoverMovie/Table/{AddListMovieTable.js => DiscoverMovieTable.js} (85%) rename frontend/src/DiscoverMovie/Table/{AddListMovieTableConnector.js => DiscoverMovieTableConnector.js} (88%) create mode 100644 frontend/src/DiscoverMovie/Table/DiscoverMovieTableOptions.js create mode 100644 frontend/src/DiscoverMovie/Table/DiscoverMovieTableOptionsConnector.js rename frontend/src/Settings/{NetImport/NetImportExclusions/EditNetImportExclusionModal.js => ImportLists/ImportExclusions/EditImportExclusionModal.js} (57%) rename frontend/src/Settings/{NetImport/NetImportExclusions/EditNetImportExclusionModalConnector.js => ImportLists/ImportExclusions/EditImportExclusionModalConnector.js} (66%) rename frontend/src/Settings/{NetImport/NetImportExclusions/EditNetImportExclusionModalContent.css => ImportLists/ImportExclusions/EditImportExclusionModalContent.css} (100%) rename frontend/src/Settings/{NetImport/NetImportExclusions/EditNetImportExclusionModalContent.js => ImportLists/ImportExclusions/EditImportExclusionModalContent.js} (91%) rename frontend/src/Settings/{NetImport/NetImportExclusions/EditNetImportExclusionModalContentConnector.js => ImportLists/ImportExclusions/EditImportExclusionModalContentConnector.js} (57%) rename frontend/src/Settings/{NetImport/NetImportExclusions/NetImportExclusion.css => ImportLists/ImportExclusions/ImportExclusion.css} (93%) rename frontend/src/Settings/{NetImport/NetImportExclusions/NetImportExclusion.js => ImportLists/ImportExclusions/ImportExclusion.js} (50%) rename frontend/src/Settings/{NetImport/NetImportExclusions/NetImportExclusions.css => ImportLists/ImportExclusions/ImportExclusions.css} (82%) rename frontend/src/Settings/{NetImport/NetImportExclusions/NetImportExclusions.js => ImportLists/ImportExclusions/ImportExclusions.js} (62%) create mode 100644 frontend/src/Settings/ImportLists/ImportExclusions/ImportExclusionsConnector.js rename frontend/src/Settings/{NetImport/NetImportSettings.js => ImportLists/ImportListSettings.js} (76%) rename frontend/src/Settings/{NetImport/NetImportSettingsConnector.js => ImportLists/ImportListSettingsConnector.js} (56%) rename frontend/src/Settings/{NetImport/NetImport/AddNetImportItem.css => ImportLists/ImportLists/AddImportListItem.css} (97%) rename frontend/src/Settings/{NetImport/NetImport/AddNetImportItem.js => ImportLists/ImportLists/AddImportListItem.js} (78%) rename frontend/src/Settings/{NetImport/NetImport/AddNetImportModal.js => ImportLists/ImportLists/AddImportListModal.js} (57%) rename frontend/src/Settings/{NetImport/NetImport/AddNetImportModalContent.css => ImportLists/ImportLists/AddImportListModalContent.css} (81%) rename frontend/src/Settings/{NetImport/NetImport/AddNetImportModalContent.js => ImportLists/ImportLists/AddImportListModalContent.js} (73%) rename frontend/src/Settings/{NetImport/NetImport/AddNetImportModalContentConnector.js => ImportLists/ImportLists/AddImportListModalContentConnector.js} (51%) rename frontend/src/Settings/{NetImport/NetImport/AddNetImportPresetMenuItem.js => ImportLists/ImportLists/AddImportListPresetMenuItem.js} (83%) rename frontend/src/Settings/{NetImport/NetImport/EditNetImportModal.js => ImportLists/ImportLists/EditImportListModal.js} (61%) create mode 100644 frontend/src/Settings/ImportLists/ImportLists/EditImportListModalConnector.js rename frontend/src/Settings/{NetImport/NetImport/EditNetImportModalContent.css => ImportLists/ImportLists/EditImportListModalContent.css} (100%) rename frontend/src/Settings/{NetImport/NetImport/EditNetImportModalContent.js => ImportLists/ImportLists/EditImportListModalContent.js} (88%) rename frontend/src/Settings/{NetImport/NetImport/EditNetImportModalContentConnector.js => ImportLists/ImportLists/EditImportListModalContentConnector.js} (57%) rename frontend/src/Settings/{NetImport/NetImport/NetImport.css => ImportLists/ImportLists/ImportList.css} (94%) rename frontend/src/Settings/{NetImport/NetImport/NetImport.js => ImportLists/ImportLists/ImportList.js} (57%) rename frontend/src/Settings/{NetImport/NetImport/NetImports.css => ImportLists/ImportLists/ImportLists.css} (77%) rename frontend/src/Settings/{NetImport/NetImport/NetImports.js => ImportLists/ImportLists/ImportLists.js} (51%) rename frontend/src/Settings/{NetImport/NetImport/NetImportsConnector.js => ImportLists/ImportLists/ImportListsConnector.js} (54%) rename frontend/src/Settings/{NetImport/Options/NetImportOptions.js => ImportLists/Options/ImportListOptions.js} (89%) rename frontend/src/Settings/{NetImport/Options/NetImportOptionsConnector.js => ImportLists/Options/ImportListOptionsConnector.js} (64%) delete mode 100644 frontend/src/Settings/NetImport/NetImport/EditNetImportModalConnector.js delete mode 100644 frontend/src/Settings/NetImport/NetImportExclusions/NetImportExclusionsConnector.js create mode 100644 frontend/src/Store/Actions/Settings/importExclusions.js create mode 100644 frontend/src/Store/Actions/Settings/importListOptions.js create mode 100644 frontend/src/Store/Actions/Settings/importLists.js delete mode 100644 frontend/src/Store/Actions/Settings/netImportExclusions.js delete mode 100644 frontend/src/Store/Actions/Settings/netImportOptions.js delete mode 100644 frontend/src/Store/Actions/Settings/netImports.js create mode 100644 frontend/src/Store/Selectors/createImportListSelector.js delete mode 100644 src/NzbDrone.Api/Movies/FetchMovieListModule.cs delete mode 100644 src/NzbDrone.Api/Movies/MovieBulkImportModule.cs delete mode 100644 src/NzbDrone.Api/NetImport/ListImportModule.cs rename src/NzbDrone.Core.Test/{NetImport => ImportListTests}/CouchPotato/CouchPotatoParserFixture.cs (73%) create mode 100644 src/NzbDrone.Core.Test/ImportListTests/FetchAndParseImportListServiceFixture.cs rename src/NzbDrone.Core.Test/{NetImport/NetImportStatusServiceFixture.cs => ImportListTests/ImportListStatusServiceFixture.cs} (61%) rename src/NzbDrone.Core.Test/{NetImport/NetImportSearchServiceFixture.cs => ImportListTests/ImportListSyncServiceFixture.cs} (54%) rename src/NzbDrone.Core.Test/{NetImport => ImportListTests}/RSSImportFixture.cs (92%) rename src/NzbDrone.Core.Test/{NetImport => ImportListTests}/RSSImportParserFixture.cs (73%) create mode 100644 src/NzbDrone.Core.Test/Messaging/Commands/CommandQueueFixture.cs delete mode 100644 src/NzbDrone.Core.Test/ThingiProvider/ProviderBaseFixture.cs create mode 100644 src/NzbDrone.Core/Datastore/Migration/181_list_movies_table.cs rename src/NzbDrone.Core/HealthCheck/Checks/{NetImportStatusCheck.cs => ImportListStatusCheck.cs} (57%) rename src/NzbDrone.Core/{NetImport/NetImportListLevels.cs => ImportLists/CleanLibraryLevel.cs} (60%) rename src/NzbDrone.Core/{NetImport => ImportLists}/CouchPotato/CouchPotatoAPI.cs (98%) create mode 100644 src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoImport.cs rename src/NzbDrone.Core/{NetImport => ImportLists}/CouchPotato/CouchPotatoParser.cs (53%) rename src/NzbDrone.Core/{NetImport => ImportLists}/CouchPotato/CouchPotatoRequestGenerator.cs (57%) rename src/NzbDrone.Core/{NetImport => ImportLists}/CouchPotato/CouchPotatoSettings.cs (97%) create mode 100644 src/NzbDrone.Core/ImportLists/Exceptions/ImportListException.cs create mode 100644 src/NzbDrone.Core/ImportLists/FetchAndParseImportListService.cs rename src/NzbDrone.Core/{NetImport/HttpNetImportBase.cs => ImportLists/HttpImportListBase.cs} (66%) create mode 100644 src/NzbDrone.Core/ImportLists/IImportList.cs create mode 100644 src/NzbDrone.Core/ImportLists/IImportListRequestGenerator.cs create mode 100644 src/NzbDrone.Core/ImportLists/IParseImportListResponse.cs rename src/NzbDrone.Core/{NetImport => ImportLists}/ImportExclusions/ImportExclusion.cs (87%) rename src/NzbDrone.Core/{NetImport => ImportLists}/ImportExclusions/ImportExclusionsRepository.cs (93%) rename src/NzbDrone.Core/{NetImport => ImportLists}/ImportExclusions/ImportExclusionsService.cs (86%) rename src/NzbDrone.Core/{NetImport/NetImportBase.cs => ImportLists/ImportListBase.cs} (66%) rename src/NzbDrone.Core/{NetImport/NetImportBaseSettings.cs => ImportLists/ImportListBaseSettings.cs} (61%) rename src/NzbDrone.Core/{NetImport/NetImportDefinition.cs => ImportLists/ImportListDefinition.cs} (64%) create mode 100644 src/NzbDrone.Core/ImportLists/ImportListFactory.cs create mode 100644 src/NzbDrone.Core/ImportLists/ImportListMovies/ImportListMovie.cs create mode 100644 src/NzbDrone.Core/ImportLists/ImportListMovies/ImportListMovieRepository.cs create mode 100644 src/NzbDrone.Core/ImportLists/ImportListMovies/ImportListMovieService.cs create mode 100644 src/NzbDrone.Core/ImportLists/ImportListPageableRequest.cs create mode 100644 src/NzbDrone.Core/ImportLists/ImportListPageableRequestChain.cs create mode 100644 src/NzbDrone.Core/ImportLists/ImportListRepository.cs rename src/NzbDrone.Core/{NetImport/NetImportRequest.cs => ImportLists/ImportListRequest.cs} (60%) rename src/NzbDrone.Core/{NetImport/NetImportResponse.cs => ImportLists/ImportListResponse.cs} (52%) rename src/NzbDrone.Core/{NetImport/NetImportStatus.cs => ImportLists/ImportListStatus.cs} (60%) create mode 100644 src/NzbDrone.Core/ImportLists/ImportListStatusRepository.cs rename src/NzbDrone.Core/{NetImport/NetImportStatusService.cs => ImportLists/ImportListStatusService.cs} (68%) create mode 100644 src/NzbDrone.Core/ImportLists/ImportListSyncCommand.cs create mode 100644 src/NzbDrone.Core/ImportLists/ImportListSyncService.cs rename src/NzbDrone.Core/{NetImport/NetImportType.cs => ImportLists/ImportListType.cs} (58%) create mode 100644 src/NzbDrone.Core/ImportLists/ImportListUpdatedHandler.cs rename src/NzbDrone.Core/{NetImport => ImportLists}/RSSImport/RSSImport.cs (68%) rename src/NzbDrone.Core/{NetImport => ImportLists}/RSSImport/RSSImportParser.cs (78%) create mode 100644 src/NzbDrone.Core/ImportLists/RSSImport/RSSImportRequestGenerator.cs rename src/NzbDrone.Core/{NetImport => ImportLists}/RSSImport/RSSImportSettings.cs (95%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Radarr/RadarrAPIResource.cs (95%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Radarr/RadarrImport.cs (75%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Radarr/RadarrSettings.cs (97%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Radarr/RadarrV3Proxy.cs (98%) rename src/NzbDrone.Core/{NetImport => ImportLists}/RadarrList/RadarrListException.cs (96%) rename src/NzbDrone.Core/{NetImport => ImportLists}/RadarrList/RadarrListImport.cs (68%) rename src/NzbDrone.Core/{NetImport => ImportLists}/RadarrList/RadarrListParser.cs (56%) create mode 100644 src/NzbDrone.Core/ImportLists/RadarrList/RadarrListRequestGenerator.cs rename src/NzbDrone.Core/{NetImport => ImportLists}/RadarrList/RadarrListSettings.cs (94%) rename src/NzbDrone.Core/{NetImport => ImportLists}/RadarrList2/IMDb/IMDbListImport.cs (77%) rename src/NzbDrone.Core/{NetImport => ImportLists}/RadarrList2/IMDb/IMDbListRequestGenerator.cs (87%) rename src/NzbDrone.Core/{NetImport => ImportLists}/RadarrList2/IMDb/IMDbListSettings.cs (95%) rename src/NzbDrone.Core/{NetImport => ImportLists}/RadarrList2/RadarrList2Parser.cs (64%) rename src/NzbDrone.Core/{NetImport => ImportLists}/RadarrList2/RadarrList2RequestGenerator.cs (52%) rename src/NzbDrone.Core/{NetImport => ImportLists}/RadarrList2/StevenLu/StevenLu2Import.cs (67%) rename src/NzbDrone.Core/{NetImport => ImportLists}/RadarrList2/StevenLu/StevenLu2RequestGenerator.cs (93%) rename src/NzbDrone.Core/{NetImport => ImportLists}/RadarrList2/StevenLu/StevenLu2Settings.cs (95%) rename src/NzbDrone.Core/{NetImport => ImportLists}/StevenLu/StevenLuAPI.cs (79%) rename src/NzbDrone.Core/{NetImport => ImportLists}/StevenLu/StevenLuImport.cs (57%) create mode 100644 src/NzbDrone.Core/ImportLists/StevenLu/StevenLuParser.cs create mode 100644 src/NzbDrone.Core/ImportLists/StevenLu/StevenLuRequestGenerator.cs rename src/NzbDrone.Core/{NetImport => ImportLists}/StevenLu/StevenLuSettings.cs (95%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/Collection/TMDbCollectionImport.cs (69%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/Collection/TMDbCollectionParser.cs (77%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/Collection/TMDbCollectionRequestGenerator.cs (72%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/Collection/TMDbCollectionSettings.cs (94%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/List/TMDbListImport.cs (69%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/List/TMDbListParser.cs (77%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/List/TMDbListRequestGenerator.cs (71%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/List/TMDbListSettings.cs (94%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/Person/TMDbPersonImport.cs (69%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/Person/TMDbPersonParser.cs (84%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/Person/TMDbPersonRequestGenerator.cs (71%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/Person/TMDbPersonSettings.cs (97%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/Popular/TMDbPopularImport.cs (69%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/Popular/TMDbPopularListType.cs (87%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/Popular/TMDbPopularRequestGenerator.cs (90%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/Popular/TMDbPopularSettings.cs (95%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/TMDBResources.cs (98%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/TMDbFilterSettings.cs (98%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/TMDbImportBase.cs (63%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/TMDbLanguageCodes.cs (86%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/TMDbParser.cs (73%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/TMDbSettings.cs (94%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/User/TMDbUserImport.cs (87%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/User/TMDbUserListType.cs (88%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/User/TMDbUserRequestGenerator.cs (82%) rename src/NzbDrone.Core/{NetImport => ImportLists}/TMDb/User/TMDbUserSettings.cs (96%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Trakt/List/TraktListImport.cs (67%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Trakt/List/TraktListRequestGenerator.cs (62%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Trakt/List/TraktListSettings.cs (94%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Trakt/Popular/TraktPopularImport.cs (66%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Trakt/Popular/TraktPopularListType.cs (93%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Trakt/Popular/TraktPopularParser.cs (80%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Trakt/Popular/TraktPopularRequestGenerator.cs (82%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Trakt/Popular/TraktPopularSettings.cs (94%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Trakt/TraktImportBase.cs (70%) create mode 100644 src/NzbDrone.Core/ImportLists/Trakt/TraktParser.cs rename src/NzbDrone.Core/{NetImport => ImportLists}/Trakt/TraktSettingsBase.cs (98%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Trakt/User/TraktUserImport.cs (67%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Trakt/User/TraktUserListType.cs (87%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Trakt/User/TraktUserRequestGenerator.cs (72%) rename src/NzbDrone.Core/{NetImport => ImportLists}/Trakt/User/TraktUserSettings.cs (94%) delete mode 100644 src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoImport.cs delete mode 100644 src/NzbDrone.Core/NetImport/Exceptions/NetImportException.cs delete mode 100644 src/NzbDrone.Core/NetImport/INetImport.cs delete mode 100644 src/NzbDrone.Core/NetImport/INetImportRequestGenerator.cs delete mode 100644 src/NzbDrone.Core/NetImport/IProcessNetImportResponse.cs delete mode 100644 src/NzbDrone.Core/NetImport/NetImportFactory.cs delete mode 100644 src/NzbDrone.Core/NetImport/NetImportPageableRequest.cs delete mode 100644 src/NzbDrone.Core/NetImport/NetImportPageableRequestChain.cs delete mode 100644 src/NzbDrone.Core/NetImport/NetImportRepository.cs delete mode 100644 src/NzbDrone.Core/NetImport/NetImportSearchService.cs delete mode 100644 src/NzbDrone.Core/NetImport/NetImportStatusRepository.cs delete mode 100644 src/NzbDrone.Core/NetImport/NetImportSyncCommand.cs delete mode 100644 src/NzbDrone.Core/NetImport/RSSImport/RSSImportRequestGenerator.cs delete mode 100644 src/NzbDrone.Core/NetImport/RadarrList/RadarrListRequestGenerator.cs delete mode 100644 src/NzbDrone.Core/NetImport/StevenLu/StevenLuParser.cs delete mode 100644 src/NzbDrone.Core/NetImport/StevenLu/StevenLuRequestGenerator.cs delete mode 100644 src/NzbDrone.Core/NetImport/Trakt/TraktParser.cs rename src/Radarr.Api.V3/{NetImport => ImportLists}/ImportExclusionsModule.cs (66%) rename src/Radarr.Api.V3/{NetImport => ImportLists}/ImportExclusionsResource.cs (92%) rename src/Radarr.Api.V3/{NetImport/NetImportModule.cs => ImportLists/ImportListModule.cs} (52%) create mode 100644 src/Radarr.Api.V3/ImportLists/ImportListMoviesModule.cs rename src/Radarr.Api.V3/{Movies/DiscoverMoviesResource.cs => ImportLists/ImportListMoviesResource.cs} (55%) rename src/Radarr.Api.V3/{NetImport/NetImportResource.cs => ImportLists/ImportListResource.cs} (73%) delete mode 100644 src/Radarr.Api.V3/Movies/DiscoverMoviesModule.cs delete mode 100644 src/Radarr.Api.V3/Movies/FetchMovieListModule.cs diff --git a/frontend/src/AddMovie/AddNewMovie/AddNewMovieConnector.js b/frontend/src/AddMovie/AddNewMovie/AddNewMovieConnector.js index a4afccdba..252d30058 100644 --- a/frontend/src/AddMovie/AddNewMovie/AddNewMovieConnector.js +++ b/frontend/src/AddMovie/AddNewMovie/AddNewMovieConnector.js @@ -4,7 +4,7 @@ import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import { clearAddMovie, lookupMovie } from 'Store/Actions/addMovieActions'; import { fetchRootFolders } from 'Store/Actions/rootFolderActions'; -import { fetchNetImportExclusions } from 'Store/Actions/Settings/netImportExclusions'; +import { fetchImportExclusions } from 'Store/Actions/Settings/importExclusions'; import parseUrl from 'Utilities/String/parseUrl'; import AddNewMovie from './AddNewMovie'; @@ -29,7 +29,7 @@ const mapDispatchToProps = { lookupMovie, clearAddMovie, fetchRootFolders, - fetchNetImportExclusions + fetchImportExclusions }; class AddNewMovieConnector extends Component { @@ -45,7 +45,7 @@ class AddNewMovieConnector extends Component { componentDidMount() { this.props.fetchRootFolders(); - this.props.fetchNetImportExclusions(); + this.props.fetchImportExclusions(); } componentWillUnmount() { @@ -102,7 +102,7 @@ AddNewMovieConnector.propTypes = { lookupMovie: PropTypes.func.isRequired, clearAddMovie: PropTypes.func.isRequired, fetchRootFolders: PropTypes.func.isRequired, - fetchNetImportExclusions: PropTypes.func.isRequired + fetchImportExclusions: PropTypes.func.isRequired }; export default connect(createMapStateToProps, mapDispatchToProps)(AddNewMovieConnector); diff --git a/frontend/src/AddMovie/AddNewMovie/AddNewMovieSearchResult.js b/frontend/src/AddMovie/AddNewMovie/AddNewMovieSearchResult.js index 8c5bb2b35..3367260ea 100644 --- a/frontend/src/AddMovie/AddNewMovie/AddNewMovieSearchResult.js +++ b/frontend/src/AddMovie/AddNewMovie/AddNewMovieSearchResult.js @@ -118,7 +118,7 @@ class AddNewMovieSearchResult extends Component { className={styles.exclusionIcon} name={icons.DANGER} size={36} - title={translate('MovieIsOnNetImportExclusionList')} + title={translate('MovieIsOnImportExclusionList')} /> } diff --git a/frontend/src/App/AppRoutes.js b/frontend/src/App/AppRoutes.js index ab899d491..0cea72088 100644 --- a/frontend/src/App/AppRoutes.js +++ b/frontend/src/App/AppRoutes.js @@ -15,10 +15,10 @@ import MovieIndexConnector from 'Movie/Index/MovieIndexConnector'; import CustomFormatSettingsConnector from 'Settings/CustomFormats/CustomFormatSettingsConnector'; import DownloadClientSettingsConnector from 'Settings/DownloadClients/DownloadClientSettingsConnector'; import GeneralSettingsConnector from 'Settings/General/GeneralSettingsConnector'; +import ImportListSettingsConnector from 'Settings/ImportLists/ImportListSettingsConnector'; import IndexerSettingsConnector from 'Settings/Indexers/IndexerSettingsConnector'; import MediaManagementConnector from 'Settings/MediaManagement/MediaManagementConnector'; import MetadataSettings from 'Settings/Metadata/MetadataSettings'; -import NetImportSettingsConnector from 'Settings/NetImport/NetImportSettingsConnector'; import NotificationSettings from 'Settings/Notifications/NotificationSettings'; import Profiles from 'Settings/Profiles/Profiles'; import Quality from 'Settings/Quality/Quality'; @@ -156,8 +156,8 @@ function AppRoutes(props) { /> { + return { + tagList: importLists.map((importList) => { + const { + id, + name + } = importList; + + return { + id, + name + }; + }) + }; + } + ); +} + +export default connect(createMapStateToProps)(FilterBuilderRowValue); diff --git a/frontend/src/Components/ImportListList.css b/frontend/src/Components/ImportListList.css new file mode 100644 index 000000000..6e6911082 --- /dev/null +++ b/frontend/src/Components/ImportListList.css @@ -0,0 +1,3 @@ +.lists { + flex: 1 0 auto; +} diff --git a/frontend/src/Components/ImportListList.js b/frontend/src/Components/ImportListList.js new file mode 100644 index 000000000..7695b26d3 --- /dev/null +++ b/frontend/src/Components/ImportListList.js @@ -0,0 +1,43 @@ +import _ from 'lodash'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { kinds, sizes } from 'Helpers/Props'; +import Label from './Label'; +import styles from './ImportListList.css'; + +function ImportListList({ lists, importListList }) { + return ( +
+ { + lists.map((t) => { + const list = _.find(importListList, { id: t }); + + if (!list) { + return null; + } + + return ( + + ); + }) + } +
+ ); +} + +ImportListList.propTypes = { + lists: PropTypes.arrayOf(PropTypes.number).isRequired, + importListList: PropTypes.arrayOf(PropTypes.object).isRequired +}; + +ImportListList.defaultProps = { + lists: [] +}; + +export default ImportListList; diff --git a/frontend/src/Components/ImportListListConnector.js b/frontend/src/Components/ImportListListConnector.js new file mode 100644 index 000000000..8f7983048 --- /dev/null +++ b/frontend/src/Components/ImportListListConnector.js @@ -0,0 +1,17 @@ +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import createImportListSelector from 'Store/Selectors/createImportListSelector'; +import ImportListList from './ImportListList'; + +function createMapStateToProps() { + return createSelector( + createImportListSelector(), + (importListList) => { + return { + importListList + }; + } + ); +} + +export default connect(createMapStateToProps)(ImportListList); diff --git a/frontend/src/Components/Page/PageConnector.js b/frontend/src/Components/Page/PageConnector.js index 67c4a9053..9dd262127 100644 --- a/frontend/src/Components/Page/PageConnector.js +++ b/frontend/src/Components/Page/PageConnector.js @@ -6,7 +6,7 @@ import { createSelector } from 'reselect'; import { saveDimensions, setIsSidebarVisible } from 'Store/Actions/appActions'; import { fetchCustomFilters } from 'Store/Actions/customFilterActions'; import { fetchMovies } from 'Store/Actions/movieActions'; -import { fetchLanguages, fetchNetImports, fetchQualityProfiles, fetchUISettings } from 'Store/Actions/settingsActions'; +import { fetchImportLists, fetchLanguages, fetchQualityProfiles, fetchUISettings } from 'Store/Actions/settingsActions'; import { fetchStatus } from 'Store/Actions/systemActions'; import { fetchTags } from 'Store/Actions/tagActions'; import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector'; @@ -48,7 +48,7 @@ const selectIsPopulated = createSelector( (state) => state.settings.ui.isPopulated, (state) => state.settings.qualityProfiles.isPopulated, (state) => state.settings.languages.isPopulated, - (state) => state.settings.netImports.isPopulated, + (state) => state.settings.importLists.isPopulated, (state) => state.system.status.isPopulated, ( customFiltersIsPopulated, @@ -56,7 +56,7 @@ const selectIsPopulated = createSelector( uiSettingsIsPopulated, qualityProfilesIsPopulated, languagesIsPopulated, - netImportsIsPopulated, + importListsIsPopulated, systemStatusIsPopulated ) => { return ( @@ -65,7 +65,7 @@ const selectIsPopulated = createSelector( uiSettingsIsPopulated && qualityProfilesIsPopulated && languagesIsPopulated && - netImportsIsPopulated && + importListsIsPopulated && systemStatusIsPopulated ); } @@ -77,7 +77,7 @@ const selectErrors = createSelector( (state) => state.settings.ui.error, (state) => state.settings.qualityProfiles.error, (state) => state.settings.languages.error, - (state) => state.settings.netImports.error, + (state) => state.settings.importLists.error, (state) => state.system.status.error, ( customFiltersError, @@ -85,7 +85,7 @@ const selectErrors = createSelector( uiSettingsError, qualityProfilesError, languagesError, - netImportsError, + importListsError, systemStatusError ) => { const hasError = !!( @@ -94,7 +94,7 @@ const selectErrors = createSelector( uiSettingsError || qualityProfilesError || languagesError || - netImportsError || + importListsError || systemStatusError ); @@ -105,7 +105,7 @@ const selectErrors = createSelector( uiSettingsError, qualityProfilesError, languagesError, - netImportsError, + importListsError, systemStatusError }; } @@ -153,8 +153,8 @@ function createMapDispatchToProps(dispatch, props) { dispatchFetchLanguages() { dispatch(fetchLanguages()); }, - dispatchFetchNetImports() { - dispatch(fetchNetImports()); + dispatchFetchImportLists() { + dispatch(fetchImportLists()); }, dispatchFetchUISettings() { dispatch(fetchUISettings()); @@ -191,7 +191,7 @@ class PageConnector extends Component { this.props.dispatchFetchTags(); this.props.dispatchFetchQualityProfiles(); this.props.dispatchFetchLanguages(); - this.props.dispatchFetchNetImports(); + this.props.dispatchFetchImportLists(); this.props.dispatchFetchUISettings(); this.props.dispatchFetchStatus(); } @@ -215,7 +215,7 @@ class PageConnector extends Component { dispatchFetchTags, dispatchFetchQualityProfiles, dispatchFetchLanguages, - dispatchFetchNetImports, + dispatchFetchImportLists, dispatchFetchUISettings, dispatchFetchStatus, ...otherProps @@ -254,7 +254,7 @@ PageConnector.propTypes = { dispatchFetchTags: PropTypes.func.isRequired, dispatchFetchQualityProfiles: PropTypes.func.isRequired, dispatchFetchLanguages: PropTypes.func.isRequired, - dispatchFetchNetImports: PropTypes.func.isRequired, + dispatchFetchImportLists: PropTypes.func.isRequired, dispatchFetchUISettings: PropTypes.func.isRequired, dispatchFetchStatus: PropTypes.func.isRequired, onSidebarVisibleChange: PropTypes.func.isRequired diff --git a/frontend/src/Components/Page/Sidebar/PageSidebar.js b/frontend/src/Components/Page/Sidebar/PageSidebar.js index 4762e2828..2c3f64750 100644 --- a/frontend/src/Components/Page/Sidebar/PageSidebar.js +++ b/frontend/src/Components/Page/Sidebar/PageSidebar.js @@ -98,7 +98,7 @@ const links = [ }, { title: translate('Lists'), - to: '/settings/netimports' + to: '/settings/importlists' }, { title: translate('Connect'), diff --git a/frontend/src/DiscoverMovie/DiscoverMovie.js b/frontend/src/DiscoverMovie/DiscoverMovie.js index c6553ec14..16059e43a 100644 --- a/frontend/src/DiscoverMovie/DiscoverMovie.js +++ b/frontend/src/DiscoverMovie/DiscoverMovie.js @@ -18,26 +18,27 @@ import getSelectedIds from 'Utilities/Table/getSelectedIds'; import selectAll from 'Utilities/Table/selectAll'; import toggleSelected from 'Utilities/Table/toggleSelected'; import DiscoverMovieFooterConnector from './DiscoverMovieFooterConnector'; -import AddListMovieFilterMenu from './Menus/AddListMovieFilterMenu'; -import AddListMovieSortMenu from './Menus/AddListMovieSortMenu'; -import AddListMovieViewMenu from './Menus/AddListMovieViewMenu'; +import DiscoverMovieFilterMenu from './Menus/DiscoverMovieFilterMenu'; +import DiscoverMovieSortMenu from './Menus/DiscoverMovieSortMenu'; +import DiscoverMovieViewMenu from './Menus/DiscoverMovieViewMenu'; import NoDiscoverMovie from './NoDiscoverMovie'; -import AddListMovieOverviewsConnector from './Overview/AddListMovieOverviewsConnector'; -import AddListMovieOverviewOptionsModal from './Overview/Options/AddListMovieOverviewOptionsModal'; -import AddListMoviePostersConnector from './Posters/AddListMoviePostersConnector'; -import AddListMoviePosterOptionsModal from './Posters/Options/AddListMoviePosterOptionsModal'; -import AddListMovieTableConnector from './Table/AddListMovieTableConnector'; +import DiscoverMovieOverviewsConnector from './Overview/DiscoverMovieOverviewsConnector'; +import DiscoverMovieOverviewOptionsModal from './Overview/Options/DiscoverMovieOverviewOptionsModal'; +import DiscoverMoviePostersConnector from './Posters/DiscoverMoviePostersConnector'; +import DiscoverMoviePosterOptionsModal from './Posters/Options/DiscoverMoviePosterOptionsModal'; +import DiscoverMovieTableConnector from './Table/DiscoverMovieTableConnector'; +import DiscoverMovieTableOptionsConnector from './Table/DiscoverMovieTableOptionsConnector'; function getViewComponent(view) { if (view === 'posters') { - return AddListMoviePostersConnector; + return DiscoverMoviePostersConnector; } if (view === 'overview') { - return AddListMovieOverviewsConnector; + return DiscoverMovieOverviewsConnector; } - return AddListMovieTableConnector; + return DiscoverMovieTableConnector; } class DiscoverMovie extends Component { @@ -212,6 +213,10 @@ class DiscoverMovie extends Component { this.onSelectAllChange({ value: !this.state.allSelected }); } + onImportListSyncPress = () => { + this.props.onImportListSyncPress(); + } + onSelectedChange = ({ id, value, shiftKey = false }) => { this.setState((state) => { return toggleSelected(state, this.props.items, id, value, shiftKey, 'tmdbId'); @@ -248,6 +253,7 @@ class DiscoverMovie extends Component { onViewSelect, onScroll, onAddMoviesPress, + isSyncingLists, ...otherProps } = this.props; @@ -272,6 +278,13 @@ class DiscoverMovie extends Component { + } - - - } - - @@ -436,13 +450,15 @@ DiscoverMovie.propTypes = { sortKey: PropTypes.string, sortDirection: PropTypes.oneOf(sortDirections.all), view: PropTypes.string.isRequired, + isSyncingLists: PropTypes.bool.isRequired, isSmallScreen: PropTypes.bool.isRequired, onSortSelect: PropTypes.func.isRequired, onFilterSelect: PropTypes.func.isRequired, onViewSelect: PropTypes.func.isRequired, onScroll: PropTypes.func.isRequired, onAddMoviesPress: PropTypes.func.isRequired, - onExcludeMoviesPress: PropTypes.func.isRequired + onExcludeMoviesPress: PropTypes.func.isRequired, + onImportListSyncPress: PropTypes.func.isRequired }; export default DiscoverMovie; diff --git a/frontend/src/DiscoverMovie/DiscoverMovieConnector.js b/frontend/src/DiscoverMovie/DiscoverMovieConnector.js index 21a4e5e65..0d78d9945 100644 --- a/frontend/src/DiscoverMovie/DiscoverMovieConnector.js +++ b/frontend/src/DiscoverMovie/DiscoverMovieConnector.js @@ -2,11 +2,14 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; +import * as commandNames from 'Commands/commandNames'; import withScrollPosition from 'Components/withScrollPosition'; -import { addMovies, addNetImportExclusions, clearAddMovie, fetchDiscoverMovies, setListMovieFilter, setListMovieSort, setListMovieTableOption, setListMovieView } from 'Store/Actions/discoverMovieActions'; +import { executeCommand } from 'Store/Actions/commandActions'; +import { addImportExclusions, addMovies, clearAddMovie, fetchDiscoverMovies, setListMovieFilter, setListMovieSort, setListMovieTableOption, setListMovieView } from 'Store/Actions/discoverMovieActions'; import { fetchRootFolders } from 'Store/Actions/rootFolderActions'; -import { fetchNetImportExclusions } from 'Store/Actions/Settings/netImportExclusions'; +import { fetchImportExclusions } from 'Store/Actions/Settings/importExclusions'; import scrollPositions from 'Store/scrollPositions'; +import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector'; import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector'; import createDiscoverMovieClientSideCollectionItemsSelector from 'Store/Selectors/createDiscoverMovieClientSideCollectionItemsSelector'; import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator'; @@ -15,13 +18,16 @@ import DiscoverMovie from './DiscoverMovie'; function createMapStateToProps() { return createSelector( createDiscoverMovieClientSideCollectionItemsSelector('discoverMovie'), + createCommandExecutingSelector(commandNames.IMPORT_LIST_SYNC), createDimensionsSelector(), ( movies, + isSyncingLists, dimensionsState ) => { return { ...movies, + isSyncingLists, isSmallScreen: dimensionsState.isSmallScreen }; } @@ -34,8 +40,8 @@ function createMapDispatchToProps(dispatch, props) { dispatch(fetchRootFolders()); }, - dispatchFetchNetImportExclusions() { - dispatch(fetchNetImportExclusions()); + dispatchFetchImportExclusions() { + dispatch(fetchImportExclusions()); }, dispatchClearListMovie() { @@ -66,8 +72,14 @@ function createMapDispatchToProps(dispatch, props) { dispatch(addMovies({ ids, addOptions })); }, - dispatchAddNetImportExclusions(exclusions) { - dispatch(addNetImportExclusions(exclusions)); + dispatchAddImportExclusions(exclusions) { + dispatch(addImportExclusions(exclusions)); + }, + + onImportListSyncPress() { + dispatch(executeCommand({ + name: commandNames.IMPORT_LIST_SYNC + })); } }; } @@ -80,7 +92,7 @@ class DiscoverMovieConnector extends Component { componentDidMount() { registerPagePopulator(this.repopulate); this.props.dispatchFetchRootFolders(); - this.props.dispatchFetchNetImportExclusions(); + this.props.dispatchFetchImportExclusions(); this.props.dispatchFetchListMovies(); } @@ -105,7 +117,7 @@ class DiscoverMovieConnector extends Component { } onExcludeMoviesPress =({ ids }) => { - this.props.dispatchAddNetImportExclusions({ ids }); + this.props.dispatchAddImportExclusions({ ids }); } // @@ -119,6 +131,7 @@ class DiscoverMovieConnector extends Component { onScroll={this.onScroll} onAddMoviesPress={this.onAddMoviesPress} onExcludeMoviesPress={this.onExcludeMoviesPress} + onSyncListsPress={this.onSyncListsPress} /> ); } @@ -127,13 +140,13 @@ class DiscoverMovieConnector extends Component { DiscoverMovieConnector.propTypes = { isSmallScreen: PropTypes.bool.isRequired, view: PropTypes.string.isRequired, - dispatchFetchNetImportExclusions: PropTypes.func.isRequired, + dispatchFetchImportExclusions: PropTypes.func.isRequired, dispatchFetchRootFolders: PropTypes.func.isRequired, dispatchFetchListMovies: PropTypes.func.isRequired, dispatchClearListMovie: PropTypes.func.isRequired, dispatchSetListMovieView: PropTypes.func.isRequired, dispatchAddMovies: PropTypes.func.isRequired, - dispatchAddNetImportExclusions: PropTypes.func.isRequired + dispatchAddImportExclusions: PropTypes.func.isRequired }; export default withScrollPosition( diff --git a/frontend/src/DiscoverMovie/AddListMovieFilterModalConnector.js b/frontend/src/DiscoverMovie/DiscoverMovieFilterModalConnector.js similarity index 100% rename from frontend/src/DiscoverMovie/AddListMovieFilterModalConnector.js rename to frontend/src/DiscoverMovie/DiscoverMovieFilterModalConnector.js diff --git a/frontend/src/DiscoverMovie/DiscoverMovieFooter.css b/frontend/src/DiscoverMovie/DiscoverMovieFooter.css index 2dc21f388..c9cf4ce4c 100644 --- a/frontend/src/DiscoverMovie/DiscoverMovieFooter.css +++ b/frontend/src/DiscoverMovie/DiscoverMovieFooter.css @@ -29,7 +29,7 @@ .excludeSelectedButton { composes: button from '~Components/Link/SpinnerButton.css'; - margin-left: 50px; + margin-left: 25px; height: 35px; } diff --git a/frontend/src/DiscoverMovie/DiscoverMovieFooterConnector.js b/frontend/src/DiscoverMovie/DiscoverMovieFooterConnector.js index 604eff4bf..6562f893f 100644 --- a/frontend/src/DiscoverMovie/DiscoverMovieFooterConnector.js +++ b/frontend/src/DiscoverMovie/DiscoverMovieFooterConnector.js @@ -8,9 +8,9 @@ import DiscoverMovieFooter from './DiscoverMovieFooter'; function createMapStateToProps() { return createSelector( (state) => state.discoverMovie, - (state) => state.settings.netImportExclusions, + (state) => state.settings.importExclusions, (state, { selectedIds }) => selectedIds, - (discoverMovie, netImportExclusions, selectedIds) => { + (discoverMovie, importExclusions, selectedIds) => { const { monitor: defaultMonitor, qualityProfileId: defaultQualityProfileId, @@ -25,7 +25,7 @@ function createMapStateToProps() { const { isSaving - } = netImportExclusions; + } = importExclusions; return { selectedCount: selectedIds.length, diff --git a/frontend/src/DiscoverMovie/AddListMovieItemConnector.js b/frontend/src/DiscoverMovie/DiscoverMovieItemConnector.js similarity index 87% rename from frontend/src/DiscoverMovie/AddListMovieItemConnector.js rename to frontend/src/DiscoverMovie/DiscoverMovieItemConnector.js index 96a23ec9a..bee5235df 100644 --- a/frontend/src/DiscoverMovie/AddListMovieItemConnector.js +++ b/frontend/src/DiscoverMovie/DiscoverMovieItemConnector.js @@ -27,7 +27,7 @@ function createMapStateToProps() { ); } -class AddListMovieItemConnector extends Component { +class DiscoverMovieItemConnector extends Component { // // Render @@ -52,9 +52,9 @@ class AddListMovieItemConnector extends Component { } } -AddListMovieItemConnector.propTypes = { +DiscoverMovieItemConnector.propTypes = { tmdbId: PropTypes.number, component: PropTypes.elementType.isRequired }; -export default connect(createMapStateToProps)(AddListMovieItemConnector); +export default connect(createMapStateToProps)(DiscoverMovieItemConnector); diff --git a/frontend/src/DiscoverMovie/Exclusion/ExcludeMovieModalContentConnector.js b/frontend/src/DiscoverMovie/Exclusion/ExcludeMovieModalContentConnector.js index e79f36271..84c314b5a 100644 --- a/frontend/src/DiscoverMovie/Exclusion/ExcludeMovieModalContentConnector.js +++ b/frontend/src/DiscoverMovie/Exclusion/ExcludeMovieModalContentConnector.js @@ -1,11 +1,11 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; -import { addNetImportExclusions } from 'Store/Actions/discoverMovieActions'; +import { addImportExclusions } from 'Store/Actions/discoverMovieActions'; import ExcludeMovieModalContent from './ExcludeMovieModalContent'; const mapDispatchToProps = { - addNetImportExclusions + addImportExclusions }; class ExcludeMovieModalContentConnector extends Component { @@ -14,7 +14,7 @@ class ExcludeMovieModalContentConnector extends Component { // Listeners onExcludePress = () => { - this.props.addNetImportExclusions({ ids: [this.props.tmdbId] }); + this.props.addImportExclusions({ ids: [this.props.tmdbId] }); this.props.onModalClose(true); } @@ -37,7 +37,7 @@ ExcludeMovieModalContentConnector.propTypes = { title: PropTypes.string.isRequired, year: PropTypes.number.isRequired, onModalClose: PropTypes.func.isRequired, - addNetImportExclusions: PropTypes.func.isRequired + addImportExclusions: PropTypes.func.isRequired }; export default connect(undefined, mapDispatchToProps)(ExcludeMovieModalContentConnector); diff --git a/frontend/src/DiscoverMovie/Menus/AddListMovieFilterMenu.js b/frontend/src/DiscoverMovie/Menus/DiscoverMovieFilterMenu.js similarity index 72% rename from frontend/src/DiscoverMovie/Menus/AddListMovieFilterMenu.js rename to frontend/src/DiscoverMovie/Menus/DiscoverMovieFilterMenu.js index 6d848e80b..717443050 100644 --- a/frontend/src/DiscoverMovie/Menus/AddListMovieFilterMenu.js +++ b/frontend/src/DiscoverMovie/Menus/DiscoverMovieFilterMenu.js @@ -1,10 +1,10 @@ import PropTypes from 'prop-types'; import React from 'react'; import FilterMenu from 'Components/Menu/FilterMenu'; -import AddListMovieFilterModalConnector from 'DiscoverMovie/AddListMovieFilterModalConnector'; +import DiscoverMovieFilterModalConnector from 'DiscoverMovie/DiscoverMovieFilterModalConnector'; import { align } from 'Helpers/Props'; -function AddListMovieFilterMenu(props) { +function DiscoverMovieFilterMenu(props) { const { selectedFilterKey, filters, @@ -20,13 +20,13 @@ function AddListMovieFilterMenu(props) { selectedFilterKey={selectedFilterKey} filters={filters} customFilters={customFilters} - filterModalConnectorComponent={AddListMovieFilterModalConnector} + filterModalConnectorComponent={DiscoverMovieFilterModalConnector} onFilterSelect={onFilterSelect} /> ); } -AddListMovieFilterMenu.propTypes = { +DiscoverMovieFilterMenu.propTypes = { selectedFilterKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, filters: PropTypes.arrayOf(PropTypes.object).isRequired, customFilters: PropTypes.arrayOf(PropTypes.object).isRequired, @@ -34,8 +34,8 @@ AddListMovieFilterMenu.propTypes = { onFilterSelect: PropTypes.func.isRequired }; -AddListMovieFilterMenu.defaultProps = { +DiscoverMovieFilterMenu.defaultProps = { showCustomFilters: false }; -export default AddListMovieFilterMenu; +export default DiscoverMovieFilterMenu; diff --git a/frontend/src/DiscoverMovie/Menus/AddListMovieSortMenu.js b/frontend/src/DiscoverMovie/Menus/DiscoverMovieSortMenu.js similarity index 80% rename from frontend/src/DiscoverMovie/Menus/AddListMovieSortMenu.js rename to frontend/src/DiscoverMovie/Menus/DiscoverMovieSortMenu.js index aea5c39b0..691c645b7 100644 --- a/frontend/src/DiscoverMovie/Menus/AddListMovieSortMenu.js +++ b/frontend/src/DiscoverMovie/Menus/DiscoverMovieSortMenu.js @@ -5,7 +5,7 @@ import SortMenu from 'Components/Menu/SortMenu'; import SortMenuItem from 'Components/Menu/SortMenuItem'; import { align, sortDirections } from 'Helpers/Props'; -function AddListMovieSortMenu(props) { +function DiscoverMovieSortMenu(props) { const { sortKey, sortDirection, @@ -64,6 +64,24 @@ function AddListMovieSortMenu(props) { Physical Release + + Digital Release + + + + Runtime + + - - - ); - } -} - -AddListMovieOverviewOptionsModalContent.propTypes = { - size: PropTypes.string.isRequired, - showStudio: PropTypes.bool.isRequired, - onChangeOverviewOption: PropTypes.func.isRequired, - onModalClose: PropTypes.func.isRequired -}; - -export default AddListMovieOverviewOptionsModalContent; diff --git a/frontend/src/DiscoverMovie/Overview/Options/AddListMovieOverviewOptionsModal.js b/frontend/src/DiscoverMovie/Overview/Options/DiscoverMovieOverviewOptionsModal.js similarity index 50% rename from frontend/src/DiscoverMovie/Overview/Options/AddListMovieOverviewOptionsModal.js rename to frontend/src/DiscoverMovie/Overview/Options/DiscoverMovieOverviewOptionsModal.js index c342d71ce..695d27c7c 100644 --- a/frontend/src/DiscoverMovie/Overview/Options/AddListMovieOverviewOptionsModal.js +++ b/frontend/src/DiscoverMovie/Overview/Options/DiscoverMovieOverviewOptionsModal.js @@ -1,15 +1,15 @@ import PropTypes from 'prop-types'; import React from 'react'; import Modal from 'Components/Modal/Modal'; -import AddListMovieOverviewOptionsModalContentConnector from './AddListMovieOverviewOptionsModalContentConnector'; +import DiscoverMovieOverviewOptionsModalContentConnector from './DiscoverMovieOverviewOptionsModalContentConnector'; -function AddListMovieOverviewOptionsModal({ isOpen, onModalClose, ...otherProps }) { +function DiscoverMovieOverviewOptionsModal({ isOpen, onModalClose, ...otherProps }) { return ( - @@ -17,9 +17,9 @@ function AddListMovieOverviewOptionsModal({ isOpen, onModalClose, ...otherProps ); } -AddListMovieOverviewOptionsModal.propTypes = { +DiscoverMovieOverviewOptionsModal.propTypes = { isOpen: PropTypes.bool.isRequired, onModalClose: PropTypes.func.isRequired }; -export default AddListMovieOverviewOptionsModal; +export default DiscoverMovieOverviewOptionsModal; diff --git a/frontend/src/DiscoverMovie/Overview/Options/DiscoverMovieOverviewOptionsModalContent.js b/frontend/src/DiscoverMovie/Overview/Options/DiscoverMovieOverviewOptionsModalContent.js new file mode 100644 index 000000000..ffb56c736 --- /dev/null +++ b/frontend/src/DiscoverMovie/Overview/Options/DiscoverMovieOverviewOptionsModalContent.js @@ -0,0 +1,239 @@ +import _ from 'lodash'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import Form from 'Components/Form/Form'; +import FormGroup from 'Components/Form/FormGroup'; +import FormInputGroup from 'Components/Form/FormInputGroup'; +import FormLabel from 'Components/Form/FormLabel'; +import Button from 'Components/Link/Button'; +import ModalBody from 'Components/Modal/ModalBody'; +import ModalContent from 'Components/Modal/ModalContent'; +import ModalFooter from 'Components/Modal/ModalFooter'; +import ModalHeader from 'Components/Modal/ModalHeader'; +import { inputTypes } from 'Helpers/Props'; +import translate from 'Utilities/String/translate'; + +const posterSizeOptions = [ + { key: 'small', value: 'Small' }, + { key: 'medium', value: 'Medium' }, + { key: 'large', value: 'Large' } +]; + +class DiscoverMovieOverviewOptionsModalContent extends Component { + + // + // Lifecycle + + constructor(props, context) { + super(props, context); + + this.state = { + size: props.size, + showStudio: props.showStudio, + showCertification: props.showCertification, + showRatings: props.showRatings, + showYear: props.showYear, + showGenres: props.showGenres, + includeRecommendations: props.includeRecommendations + }; + } + + componentDidUpdate(prevProps) { + const { + size, + showStudio, + showYear, + showRatings, + showCertification, + showGenres, + includeRecommendations + } = this.props; + + const state = {}; + + if (size !== prevProps.size) { + state.size = size; + } + + if (showStudio !== prevProps.showStudio) { + state.showStudio = showStudio; + } + + if (showYear !== prevProps.showYear) { + state.showYear = showYear; + } + + if (showRatings !== prevProps.showRatings) { + state.showRatings = showRatings; + } + + if (showCertification !== prevProps.showCertification) { + state.showCertification = showCertification; + } + + if (showGenres !== prevProps.showGenres) { + state.showGenres = showGenres; + } + + if (includeRecommendations !== prevProps.includeRecommendations) { + state.includeRecommendations = includeRecommendations; + } + + if (!_.isEmpty(state)) { + this.setState(state); + } + } + + // + // Listeners + + onChangeOverviewOption = ({ name, value }) => { + this.setState({ + [name]: value + }, () => { + this.props.onChangeOverviewOption({ [name]: value }); + }); + } + + onChangeOption = ({ name, value }) => { + this.setState({ + [name]: value + }, () => { + this.props.onChangeOption({ + [name]: value + }); + }); + } + + // + // Render + + render() { + const { + onModalClose + } = this.props; + + const { + size, + showStudio, + showCertification, + showRatings, + showYear, + showGenres, + includeRecommendations + } = this.state; + + return ( + + + Overview Options + + + +
+ + Include Radarr Recommendations + + + + + {translate('PosterSize')} + + + + + + Show Genres + + + + + + {translate('ShowStudio')} + + + + + + Show Year + + + + + + Show Ratings + + + + + + Show Certification + + + +
+
+ + + + +
+ ); + } +} + +DiscoverMovieOverviewOptionsModalContent.propTypes = { + size: PropTypes.string.isRequired, + showStudio: PropTypes.bool.isRequired, + showYear: PropTypes.bool.isRequired, + showRatings: PropTypes.bool.isRequired, + showCertification: PropTypes.bool.isRequired, + showGenres: PropTypes.bool.isRequired, + includeRecommendations: PropTypes.bool.isRequired, + onChangeOverviewOption: PropTypes.func.isRequired, + onChangeOption: PropTypes.func.isRequired, + onModalClose: PropTypes.func.isRequired +}; + +export default DiscoverMovieOverviewOptionsModalContent; diff --git a/frontend/src/DiscoverMovie/Overview/Options/AddListMovieOverviewOptionsModalContentConnector.js b/frontend/src/DiscoverMovie/Overview/Options/DiscoverMovieOverviewOptionsModalContentConnector.js similarity index 51% rename from frontend/src/DiscoverMovie/Overview/Options/AddListMovieOverviewOptionsModalContentConnector.js rename to frontend/src/DiscoverMovie/Overview/Options/DiscoverMovieOverviewOptionsModalContentConnector.js index 585a13d1d..366a091ef 100644 --- a/frontend/src/DiscoverMovie/Overview/Options/AddListMovieOverviewOptionsModalContentConnector.js +++ b/frontend/src/DiscoverMovie/Overview/Options/DiscoverMovieOverviewOptionsModalContentConnector.js @@ -1,13 +1,16 @@ import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { setListMovieOverviewOption } from 'Store/Actions/discoverMovieActions'; -import AddListMovieOverviewOptionsModalContent from './AddListMovieOverviewOptionsModalContent'; +import { setListMovieOption, setListMovieOverviewOption } from 'Store/Actions/discoverMovieActions'; +import DiscoverMovieOverviewOptionsModalContent from './DiscoverMovieOverviewOptionsModalContent'; function createMapStateToProps() { return createSelector( (state) => state.discoverMovie, (discoverMovie) => { - return discoverMovie.overviewOptions; + return { + ...discoverMovie.options, + ...discoverMovie.overviewOptions + }; } ); } @@ -16,8 +19,11 @@ function createMapDispatchToProps(dispatch, props) { return { onChangeOverviewOption(payload) { dispatch(setListMovieOverviewOption(payload)); + }, + onChangeOption(payload) { + dispatch(setListMovieOption(payload)); } }; } -export default connect(createMapStateToProps, createMapDispatchToProps)(AddListMovieOverviewOptionsModalContent); +export default connect(createMapStateToProps, createMapDispatchToProps)(DiscoverMovieOverviewOptionsModalContent); diff --git a/frontend/src/DiscoverMovie/Posters/AddListMoviePosterInfo.js b/frontend/src/DiscoverMovie/Posters/AddListMoviePosterInfo.js deleted file mode 100644 index 732032cf1..000000000 --- a/frontend/src/DiscoverMovie/Posters/AddListMoviePosterInfo.js +++ /dev/null @@ -1,30 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import styles from './AddListMoviePosterInfo.css'; - -function AddListMoviePosterInfo(props) { - const { - studio, - sortKey - } = props; - - if (sortKey === 'studio' && studio) { - return ( -
- {studio} -
- ); - } - - return null; -} - -AddListMoviePosterInfo.propTypes = { - studio: PropTypes.string, - sortKey: PropTypes.string.isRequired, - showRelativeDates: PropTypes.bool.isRequired, - shortDateFormat: PropTypes.string.isRequired, - timeFormat: PropTypes.string.isRequired -}; - -export default AddListMoviePosterInfo; diff --git a/frontend/src/DiscoverMovie/Posters/AddListMoviePoster.css b/frontend/src/DiscoverMovie/Posters/DiscoverMoviePoster.css similarity index 100% rename from frontend/src/DiscoverMovie/Posters/AddListMoviePoster.css rename to frontend/src/DiscoverMovie/Posters/DiscoverMoviePoster.css diff --git a/frontend/src/DiscoverMovie/Posters/AddListMoviePoster.js b/frontend/src/DiscoverMovie/Posters/DiscoverMoviePoster.js similarity index 90% rename from frontend/src/DiscoverMovie/Posters/AddListMoviePoster.js rename to frontend/src/DiscoverMovie/Posters/DiscoverMoviePoster.js index 6324454d8..83b7a29d1 100644 --- a/frontend/src/DiscoverMovie/Posters/AddListMoviePoster.js +++ b/frontend/src/DiscoverMovie/Posters/DiscoverMoviePoster.js @@ -12,9 +12,10 @@ import { icons } from 'Helpers/Props'; import MovieDetailsLinks from 'Movie/Details/MovieDetailsLinks'; import MoviePoster from 'Movie/MoviePoster'; import translate from 'Utilities/String/translate'; -import styles from './AddListMoviePoster.css'; +import DiscoverMoviePosterInfo from './DiscoverMoviePosterInfo'; +import styles from './DiscoverMoviePoster.css'; -class AddListMoviePoster extends Component { +class DiscoverMoviePoster extends Component { // // Lifecycle @@ -81,14 +82,17 @@ class AddListMoviePoster extends Component { year, overview, folder, - titleSlug, images, posterWidth, posterHeight, showTitle, isExisting, isExcluded, - isSelected + isSelected, + showRelativeDates, + shortDateFormat, + timeFormat, + ...otherProps } = this.props; const { @@ -97,7 +101,7 @@ class AddListMoviePoster extends Component { isExcludeMovieModalOpen } = this.state; - const linkProps = isExisting ? { to: `/movie/${titleSlug}` } : { onPress: this.onPress }; + const linkProps = isExisting ? { to: `/movie/${tmdbId}` } : { onPress: this.onPress }; const elementStyle = { width: `${posterWidth}px`, @@ -186,6 +190,13 @@ class AddListMoviePoster extends Component { } + + + {getMovieStatusDetails(status).title} + + ); + } + + if (sortKey === 'studio' && studio) { + return ( +
+ {studio} +
+ ); + } + + if (sortKey === 'inCinemas' && inCinemas) { + const inCinemasDate = getRelativeDate( + inCinemas, + shortDateFormat, + showRelativeDates, + { + timeFormat, + timeForToday: false + } + ); + + return ( +
+ {`In Cinemas ${inCinemasDate}`} +
+ ); + } + + if (sortKey === 'digitalRelease' && digitalRelease) { + const digitalReleaseDate = getRelativeDate( + digitalRelease, + shortDateFormat, + showRelativeDates, + { + timeFormat, + timeForToday: false + } + ); + + return ( +
+ {`Digital ${digitalReleaseDate}`} +
+ ); + } + + if (sortKey === 'physicalRelease' && physicalRelease) { + const physicalReleaseDate = getRelativeDate( + physicalRelease, + shortDateFormat, + showRelativeDates, + { + timeFormat, + timeForToday: false + } + ); + + return ( +
+ {`Released ${physicalReleaseDate}`} +
+ ); + } + + if (sortKey === 'certification' && certification) { + return ( +
+ {certification} +
+ ); + } + + if (sortKey === 'runtime' && runtime) { + return ( +
+ {formatRuntime(runtime)} +
+ ); + } + + if (sortKey === 'ratings' && ratings) { + return ( +
+ +
+ ); + } + + return null; +} + +DiscoverMoviePosterInfo.propTypes = { + status: PropTypes.string, + studio: PropTypes.string, + inCinemas: PropTypes.string, + certification: PropTypes.string, + digitalRelease: PropTypes.string, + physicalRelease: PropTypes.string, + runtime: PropTypes.number, + ratings: PropTypes.object, + sortKey: PropTypes.string.isRequired, + showRelativeDates: PropTypes.bool.isRequired, + shortDateFormat: PropTypes.string.isRequired, + timeFormat: PropTypes.string.isRequired +}; + +export default DiscoverMoviePosterInfo; diff --git a/frontend/src/DiscoverMovie/Posters/AddListMoviePosters.css b/frontend/src/DiscoverMovie/Posters/DiscoverMoviePosters.css similarity index 100% rename from frontend/src/DiscoverMovie/Posters/AddListMoviePosters.css rename to frontend/src/DiscoverMovie/Posters/DiscoverMoviePosters.css diff --git a/frontend/src/DiscoverMovie/Posters/AddListMoviePosters.js b/frontend/src/DiscoverMovie/Posters/DiscoverMoviePosters.js similarity index 94% rename from frontend/src/DiscoverMovie/Posters/AddListMoviePosters.js rename to frontend/src/DiscoverMovie/Posters/DiscoverMoviePosters.js index 0efd6f7ba..138612a38 100644 --- a/frontend/src/DiscoverMovie/Posters/AddListMoviePosters.js +++ b/frontend/src/DiscoverMovie/Posters/DiscoverMoviePosters.js @@ -2,12 +2,12 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { Grid, WindowScroller } from 'react-virtualized'; import Measure from 'Components/Measure'; -import AddListMovieItemConnector from 'DiscoverMovie/AddListMovieItemConnector'; +import DiscoverMovieItemConnector from 'DiscoverMovie/DiscoverMovieItemConnector'; import dimensions from 'Styles/Variables/dimensions'; import getIndexOfFirstCharacter from 'Utilities/Array/getIndexOfFirstCharacter'; import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder'; -import AddListMoviePosterConnector from './AddListMoviePosterConnector'; -import styles from './AddListMoviePosters.css'; +import DiscoverMoviePosterConnector from './DiscoverMoviePosterConnector'; +import styles from './DiscoverMoviePosters.css'; // Poster container dimensions const columnPadding = parseInt(dimensions.movieIndexColumnPadding); @@ -65,7 +65,7 @@ function calculatePosterHeight(posterWidth) { return Math.ceil((250 / 170) * posterWidth); } -class AddListMoviePosters extends Component { +class DiscoverMoviePosters extends Component { // // Lifecycle @@ -201,9 +201,9 @@ class AddListMoviePosters extends Component { padding: this._padding }} > - - @@ -17,9 +17,9 @@ function AddListMoviePosterOptionsModal({ isOpen, onModalClose, ...otherProps }) ); } -AddListMoviePosterOptionsModal.propTypes = { +DiscoverMoviePosterOptionsModal.propTypes = { isOpen: PropTypes.bool.isRequired, onModalClose: PropTypes.func.isRequired }; -export default AddListMoviePosterOptionsModal; +export default DiscoverMoviePosterOptionsModal; diff --git a/frontend/src/DiscoverMovie/Posters/Options/AddListMoviePosterOptionsModalContent.js b/frontend/src/DiscoverMovie/Posters/Options/DiscoverMoviePosterOptionsModalContent.js similarity index 70% rename from frontend/src/DiscoverMovie/Posters/Options/AddListMoviePosterOptionsModalContent.js rename to frontend/src/DiscoverMovie/Posters/Options/DiscoverMoviePosterOptionsModalContent.js index 6accf5a21..76806df29 100644 --- a/frontend/src/DiscoverMovie/Posters/Options/AddListMoviePosterOptionsModalContent.js +++ b/frontend/src/DiscoverMovie/Posters/Options/DiscoverMoviePosterOptionsModalContent.js @@ -19,7 +19,7 @@ const posterSizeOptions = [ { key: 'large', value: 'Large' } ]; -class AddListMoviePosterOptionsModalContent extends Component { +class DiscoverMoviePosterOptionsModalContent extends Component { // // Lifecycle @@ -29,14 +29,16 @@ class AddListMoviePosterOptionsModalContent extends Component { this.state = { size: props.size, - showTitle: props.showTitle + showTitle: props.showTitle, + includeRecommendations: props.includeRecommendations }; } componentDidUpdate(prevProps) { const { size, - showTitle + showTitle, + includeRecommendations } = this.props; const state = {}; @@ -49,6 +51,10 @@ class AddListMoviePosterOptionsModalContent extends Component { state.showTitle = showTitle; } + if (includeRecommendations !== prevProps.includeRecommendations) { + state.includeRecommendations = includeRecommendations; + } + if (!_.isEmpty(state)) { this.setState(state); } @@ -65,6 +71,16 @@ class AddListMoviePosterOptionsModalContent extends Component { }); } + onChangeOption = ({ name, value }) => { + this.setState({ + [name]: value + }, () => { + this.props.onChangeOption({ + [name]: value + }); + }); + } + // // Render @@ -75,7 +91,8 @@ class AddListMoviePosterOptionsModalContent extends Component { const { size, - showTitle + showTitle, + includeRecommendations } = this.state; return ( @@ -86,6 +103,18 @@ class AddListMoviePosterOptionsModalContent extends Component {
+ + Include Radarr Recommendations + + + + {translate('PosterSize')} @@ -124,11 +153,13 @@ class AddListMoviePosterOptionsModalContent extends Component { } } -AddListMoviePosterOptionsModalContent.propTypes = { +DiscoverMoviePosterOptionsModalContent.propTypes = { size: PropTypes.string.isRequired, showTitle: PropTypes.bool.isRequired, + includeRecommendations: PropTypes.bool.isRequired, onChangePosterOption: PropTypes.func.isRequired, + onChangeOption: PropTypes.func.isRequired, onModalClose: PropTypes.func.isRequired }; -export default AddListMoviePosterOptionsModalContent; +export default DiscoverMoviePosterOptionsModalContent; diff --git a/frontend/src/DiscoverMovie/Posters/Options/AddListMoviePosterOptionsModalContentConnector.js b/frontend/src/DiscoverMovie/Posters/Options/DiscoverMoviePosterOptionsModalContentConnector.js similarity index 51% rename from frontend/src/DiscoverMovie/Posters/Options/AddListMoviePosterOptionsModalContentConnector.js rename to frontend/src/DiscoverMovie/Posters/Options/DiscoverMoviePosterOptionsModalContentConnector.js index 9416f13fc..0ff0b3845 100644 --- a/frontend/src/DiscoverMovie/Posters/Options/AddListMoviePosterOptionsModalContentConnector.js +++ b/frontend/src/DiscoverMovie/Posters/Options/DiscoverMoviePosterOptionsModalContentConnector.js @@ -1,13 +1,16 @@ import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { setListMoviePosterOption } from 'Store/Actions/discoverMovieActions'; -import AddListMoviePosterOptionsModalContent from './AddListMoviePosterOptionsModalContent'; +import { setListMovieOption, setListMoviePosterOption } from 'Store/Actions/discoverMovieActions'; +import DiscoverMoviePosterOptionsModalContent from './DiscoverMoviePosterOptionsModalContent'; function createMapStateToProps() { return createSelector( (state) => state.discoverMovie, (discoverMovie) => { - return discoverMovie.posterOptions; + return { + ...discoverMovie.options, + ...discoverMovie.posterOptions + }; } ); } @@ -16,8 +19,11 @@ function createMapDispatchToProps(dispatch, props) { return { onChangePosterOption(payload) { dispatch(setListMoviePosterOption(payload)); + }, + onChangeOption(payload) { + dispatch(setListMovieOption(payload)); } }; } -export default connect(createMapStateToProps, createMapDispatchToProps)(AddListMoviePosterOptionsModalContent); +export default connect(createMapStateToProps, createMapDispatchToProps)(DiscoverMoviePosterOptionsModalContent); diff --git a/frontend/src/DiscoverMovie/Table/AddListMovieActionsCell.js b/frontend/src/DiscoverMovie/Table/DiscoverMovieActionsCell.js similarity index 89% rename from frontend/src/DiscoverMovie/Table/AddListMovieActionsCell.js rename to frontend/src/DiscoverMovie/Table/DiscoverMovieActionsCell.js index 4b030e195..dfb41a424 100644 --- a/frontend/src/DiscoverMovie/Table/AddListMovieActionsCell.js +++ b/frontend/src/DiscoverMovie/Table/DiscoverMovieActionsCell.js @@ -2,7 +2,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell'; -class AddListMovieActionsCell extends Component { +class DiscoverMovieActionsCell extends Component { // // Render @@ -47,8 +47,8 @@ class AddListMovieActionsCell extends Component { } } -AddListMovieActionsCell.propTypes = { +DiscoverMovieActionsCell.propTypes = { id: PropTypes.number.isRequired }; -export default AddListMovieActionsCell; +export default DiscoverMovieActionsCell; diff --git a/frontend/src/DiscoverMovie/Table/AddListMovieHeader.css b/frontend/src/DiscoverMovie/Table/DiscoverMovieHeader.css similarity index 68% rename from frontend/src/DiscoverMovie/Table/AddListMovieHeader.css rename to frontend/src/DiscoverMovie/Table/DiscoverMovieHeader.css index c897aee7d..d3a880fca 100644 --- a/frontend/src/DiscoverMovie/Table/AddListMovieHeader.css +++ b/frontend/src/DiscoverMovie/Table/DiscoverMovieHeader.css @@ -1,9 +1,10 @@ .status { composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css'; - flex: 0 0 60px; + flex: 0 0 30px; } +.collection, .sortTitle { composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css'; @@ -18,23 +19,36 @@ .inCinemas, .physicalRelease, +.digitalRelease, .genres { composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css'; flex: 0 0 180px; } -.movieStatus, +.ratings, +.runtime { + composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css'; + + flex: 0 0 90px; +} + +.lists { + composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css'; + + flex: 1 0 110px; +} + .certification { composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css'; - flex: 0 0 100px; + flex: 0 0 115px; } -.ratings { +.isRecommendation { composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css'; - flex: 0 0 80px; + flex: 0 0 50px; } .actions { diff --git a/frontend/src/DiscoverMovie/Table/AddListMovieHeader.js b/frontend/src/DiscoverMovie/Table/DiscoverMovieHeader.js similarity index 77% rename from frontend/src/DiscoverMovie/Table/AddListMovieHeader.js rename to frontend/src/DiscoverMovie/Table/DiscoverMovieHeader.js index 79756ddd0..024fd35c6 100644 --- a/frontend/src/DiscoverMovie/Table/AddListMovieHeader.js +++ b/frontend/src/DiscoverMovie/Table/DiscoverMovieHeader.js @@ -1,14 +1,16 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; +import Icon from 'Components/Icon'; import IconButton from 'Components/Link/IconButton'; import TableOptionsModal from 'Components/Table/TableOptions/TableOptionsModal'; import VirtualTableHeader from 'Components/Table/VirtualTableHeader'; import VirtualTableHeaderCell from 'Components/Table/VirtualTableHeaderCell'; import VirtualTableSelectAllHeaderCell from 'Components/Table/VirtualTableSelectAllHeaderCell'; import { icons } from 'Helpers/Props'; -import styles from './AddListMovieHeader.css'; +import DiscoverMovieTableOptionsConnector from './DiscoverMovieTableOptionsConnector'; +import styles from './DiscoverMovieHeader.css'; -class AddListMovieHeader extends Component { +class DiscoverMovieHeader extends Component { // // Lifecycle @@ -84,6 +86,23 @@ class AddListMovieHeader extends Component { ); } + if (name === 'isRecommendation') { + return ( + + + + ); + } + return ( @@ -109,7 +129,7 @@ class AddListMovieHeader extends Component { } } -AddListMovieHeader.propTypes = { +DiscoverMovieHeader.propTypes = { columns: PropTypes.arrayOf(PropTypes.object).isRequired, onTableOptionChange: PropTypes.func.isRequired, allSelected: PropTypes.bool.isRequired, @@ -117,4 +137,4 @@ AddListMovieHeader.propTypes = { onSelectAllChange: PropTypes.func.isRequired }; -export default AddListMovieHeader; +export default DiscoverMovieHeader; diff --git a/frontend/src/DiscoverMovie/Table/AddListMovieHeaderConnector.js b/frontend/src/DiscoverMovie/Table/DiscoverMovieHeaderConnector.js similarity index 66% rename from frontend/src/DiscoverMovie/Table/AddListMovieHeaderConnector.js rename to frontend/src/DiscoverMovie/Table/DiscoverMovieHeaderConnector.js index f4b9551c8..422e67cff 100644 --- a/frontend/src/DiscoverMovie/Table/AddListMovieHeaderConnector.js +++ b/frontend/src/DiscoverMovie/Table/DiscoverMovieHeaderConnector.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import { setListMovieTableOption } from 'Store/Actions/discoverMovieActions'; -import AddListMovieHeader from './AddListMovieHeader'; +import DiscoverMovieHeader from './DiscoverMovieHeader'; function createMapDispatchToProps(dispatch, props) { return { @@ -10,4 +10,4 @@ function createMapDispatchToProps(dispatch, props) { }; } -export default connect(undefined, createMapDispatchToProps)(AddListMovieHeader); +export default connect(undefined, createMapDispatchToProps)(DiscoverMovieHeader); diff --git a/frontend/src/DiscoverMovie/Table/AddListMovieRow.css b/frontend/src/DiscoverMovie/Table/DiscoverMovieRow.css similarity index 63% rename from frontend/src/DiscoverMovie/Table/AddListMovieRow.css rename to frontend/src/DiscoverMovie/Table/DiscoverMovieRow.css index 8f4ef7330..48c9c6825 100644 --- a/frontend/src/DiscoverMovie/Table/AddListMovieRow.css +++ b/frontend/src/DiscoverMovie/Table/DiscoverMovieRow.css @@ -8,7 +8,19 @@ .status { composes: cell; - flex: 0 0 60px; + flex: 0 0 30px; +} + +.alreadyExistsIcon { + width: 20px !important; + color: #37bc9b; + pointer-events: all; +} + +.exclusionIcon { + width: 20px !important; + color: $dangerColor; + pointer-events: all; } .collection, @@ -26,29 +38,36 @@ .inCinemas, .physicalRelease, +.digitalRelease, .genres { composes: cell; flex: 0 0 180px; } -.movieStatus, .certification { composes: cell; - flex: 0 0 100px; + flex: 0 0 115px; +} + +.ratings, +.runtime { + composes: cell; + + flex: 0 0 90px; } -.ratings { +.lists { composes: cell; - flex: 0 0 80px; + flex: 1 0 110px; } -.tags { +.isRecommendation { composes: cell; - flex: 1 0 60px; + flex: 0 0 50px; } .actions { diff --git a/frontend/src/DiscoverMovie/Table/AddListMovieRow.js b/frontend/src/DiscoverMovie/Table/DiscoverMovieRow.js similarity index 70% rename from frontend/src/DiscoverMovie/Table/AddListMovieRow.js rename to frontend/src/DiscoverMovie/Table/DiscoverMovieRow.js index 77816d217..f71ce5987 100644 --- a/frontend/src/DiscoverMovie/Table/AddListMovieRow.js +++ b/frontend/src/DiscoverMovie/Table/DiscoverMovieRow.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import HeartRating from 'Components/HeartRating'; import Icon from 'Components/Icon'; +import ImportListListConnector from 'Components/ImportListListConnector'; import IconButton from 'Components/Link/IconButton'; import Link from 'Components/Link/Link'; import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector'; @@ -12,11 +13,12 @@ import AddNewDiscoverMovieModal from 'DiscoverMovie/AddNewDiscoverMovieModal'; import ExcludeMovieModal from 'DiscoverMovie/Exclusion/ExcludeMovieModal'; import { icons } from 'Helpers/Props'; import MovieDetailsLinks from 'Movie/Details/MovieDetailsLinks'; +import formatRuntime from 'Utilities/Date/formatRuntime'; import translate from 'Utilities/String/translate'; import ListMovieStatusCell from './ListMovieStatusCell'; -import styles from './AddListMovieRow.css'; +import styles from './DiscoverMovieRow.css'; -class AddListMovieRow extends Component { +class DiscoverMovieRow extends Component { // // Lifecycle @@ -59,10 +61,11 @@ class AddListMovieRow extends Component { imdbId, youTubeTrailerId, title, - titleSlug, studio, inCinemas, physicalRelease, + digitalRelease, + runtime, year, overview, folder, @@ -70,10 +73,13 @@ class AddListMovieRow extends Component { genres, ratings, certification, + collection, columns, isExisting, isExcluded, + isRecommendation, isSelected, + lists, onSelectedChange } = this.props; @@ -82,7 +88,7 @@ class AddListMovieRow extends Component { isExcludeMovieModalOpen } = this.state; - const linkProps = isExisting ? { to: `/movie/${titleSlug}` } : { onPress: this.onAddMoviePress }; + const linkProps = isExisting ? { to: `/movie/${tmdbId}` } : { onPress: this.onAddMoviePress }; return ( <> @@ -113,6 +119,7 @@ class AddListMovieRow extends Component { className={styles[name]} status={status} isExclusion={isExcluded} + isExisting={isExisting} component={VirtualTableRowCell} /> ); @@ -129,6 +136,35 @@ class AddListMovieRow extends Component { > {title} + + { + isExisting ? + : null + } + + { + isExcluded ? + : null + } + + ); + } + + if (name === 'collection') { + return ( + + {collection ? collection.name : null } ); } @@ -166,6 +202,28 @@ class AddListMovieRow extends Component { ); } + if (name === 'digitalRelease') { + return ( + + ); + } + + if (name === 'runtime') { + return ( + + {formatRuntime(runtime)} + + ); + } + if (name === 'genres') { const joinedGenres = genres.join(', '); @@ -205,6 +263,38 @@ class AddListMovieRow extends Component { ); } + if (name === 'lists') { + return ( + + + + ); + } + + if (name === 'isRecommendation') { + return ( + + { + isRecommendation ? + : + null + } + + ); + } + if (name === 'actions') { return ( - { + this.setState({ + [name]: value + }, () => { + this.props.onChangeOption({ + [name]: value + }); + }); + } + + // + // Render + + render() { + const { + includeRecommendations + } = this.state; + + return ( + + Include Radarr Recommendations + + + + ); + } +} + +DiscoverMovieTableOptions.propTypes = { + includeRecommendations: PropTypes.bool.isRequired, + onChangeOption: PropTypes.func.isRequired +}; + +export default DiscoverMovieTableOptions; diff --git a/frontend/src/DiscoverMovie/Table/DiscoverMovieTableOptionsConnector.js b/frontend/src/DiscoverMovie/Table/DiscoverMovieTableOptionsConnector.js new file mode 100644 index 000000000..9084a7e29 --- /dev/null +++ b/frontend/src/DiscoverMovie/Table/DiscoverMovieTableOptionsConnector.js @@ -0,0 +1,24 @@ +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import { setListMovieOption } from 'Store/Actions/discoverMovieActions'; +import DiscoverMovieTableOptions from './DiscoverMovieTableOptions'; + +function createMapStateToProps() { + return createSelector( + (state) => state.discoverMovie, + (discoverMovie) => { + return discoverMovie.options; + } + ); +} + +function createMapDispatchToProps(dispatch, props) { + return { + onChangeOption(payload) { + dispatch(setListMovieOption(payload)); + } + }; +} + +export default connect(createMapStateToProps, createMapDispatchToProps)(DiscoverMovieTableOptions); + diff --git a/frontend/src/DiscoverMovie/Table/ListMovieStatusCell.css b/frontend/src/DiscoverMovie/Table/ListMovieStatusCell.css index 441cd6669..a3e4e82f1 100644 --- a/frontend/src/DiscoverMovie/Table/ListMovieStatusCell.css +++ b/frontend/src/DiscoverMovie/Table/ListMovieStatusCell.css @@ -1,13 +1,3 @@ -.status { - composes: cell from '~Components/Table/Cells/TableRowCell.css'; - - width: 60px; -} - .statusIcon { width: 20px !important; } - -.exclusionIcon { - color: $dangerColor; -} diff --git a/frontend/src/DiscoverMovie/Table/ListMovieStatusCell.js b/frontend/src/DiscoverMovie/Table/ListMovieStatusCell.js index 12c9a116c..db8241790 100644 --- a/frontend/src/DiscoverMovie/Table/ListMovieStatusCell.js +++ b/frontend/src/DiscoverMovie/Table/ListMovieStatusCell.js @@ -2,7 +2,6 @@ import PropTypes from 'prop-types'; import React from 'react'; import Icon from 'Components/Icon'; import VirtualTableRowCell from 'Components/Table/Cells/TableRowCell'; -import { icons } from 'Helpers/Props'; import { getMovieStatusDetails } from 'Movie/MovieStatus'; import styles from './ListMovieStatusCell.css'; @@ -10,7 +9,6 @@ function ListMovieStatusCell(props) { const { className, status, - isExclusion, component: Component, ...otherProps } = props; @@ -28,15 +26,6 @@ function ListMovieStatusCell(props) { title={`${statusDetails.title}: ${statusDetails.message}`} /> - { - isExclusion ? - : null - } - ); } @@ -44,7 +33,6 @@ function ListMovieStatusCell(props) { ListMovieStatusCell.propTypes = { className: PropTypes.string.isRequired, status: PropTypes.string.isRequired, - isExclusion: PropTypes.bool.isRequired, component: PropTypes.elementType }; diff --git a/frontend/src/Helpers/Props/filterBuilderValueTypes.js b/frontend/src/Helpers/Props/filterBuilderValueTypes.js index 0e9544bbc..db340d046 100644 --- a/frontend/src/Helpers/Props/filterBuilderValueTypes.js +++ b/frontend/src/Helpers/Props/filterBuilderValueTypes.js @@ -8,3 +8,4 @@ export const QUALITY = 'quality'; export const QUALITY_PROFILE = 'qualityProfile'; export const MOVIE_STATUS = 'movieStatus'; export const TAG = 'tag'; +export const IMPORTLIST = 'importList'; diff --git a/frontend/src/Helpers/Props/icons.js b/frontend/src/Helpers/Props/icons.js index b4abcb00a..0e90d9287 100644 --- a/frontend/src/Helpers/Props/icons.js +++ b/frontend/src/Helpers/Props/icons.js @@ -29,6 +29,7 @@ import { faBookReader as fasBookReader, faBroadcastTower as fasBroadcastTower, faBug as fasBug, + faBuilding as fasBuilding, faBullhorn as fasBullhorn, faCalendarAlt as fasCalendarAlt, faCaretDown as fasCaretDown, @@ -92,7 +93,9 @@ import { faTable as fasTable, faTags as fasTags, faTh as fasTh, + faTheaterMasks as fasTheaterMasks, faThList as fasThList, + faThumbsUp as fasThumbsUp, faTicketAlt as fasTicketAlt, faTimes as fasTimes, faTimesCircle as fasTimesCircle, @@ -145,10 +148,12 @@ export const EXPAND_INDETERMINATE = fasChevronCircleRight; export const EXTERNAL_LINK = fasExternalLinkAlt; export const FATAL = fasTimesCircle; export const FILE = farFile; +export const FILM = fasFilm; export const FILTER = fasFilter; export const FLAG = fasFlag; export const FOLDER = farFolder; export const FOLDER_OPEN = fasFolderOpen; +export const GENRE = fasTheaterMasks; export const GROUP = farObjectGroup; export const HEALTH = fasMedkit; export const HEART = fasHeart; @@ -180,6 +185,7 @@ export const PROFILE = fasUser; export const POSTER = fasTh; export const QUEUED = fasCloud; export const QUICK = fasRocket; +export const RECOMMENDED = fasThumbsUp; export const REFRESH = fasSync; export const REMOVE = fasTimes; export const RESTART = fasRedoAlt; @@ -199,7 +205,7 @@ export const SORT = fasSort; export const SORT_ASCENDING = fasSortUp; export const SORT_DESCENDING = fasSortDown; export const SPINNER = fasSpinner; -export const STUDIO = fasFilm; +export const STUDIO = fasBuilding; export const SUBTRACT = fasMinus; export const SYSTEM = fasLaptop; export const TABLE = fasTable; diff --git a/frontend/src/Movie/Delete/DeleteMovieModalContent.js b/frontend/src/Movie/Delete/DeleteMovieModalContent.js index b2fbaa351..f4eec2b8a 100644 --- a/frontend/src/Movie/Delete/DeleteMovieModalContent.js +++ b/frontend/src/Movie/Delete/DeleteMovieModalContent.js @@ -24,7 +24,7 @@ class DeleteMovieModalContent extends Component { this.state = { deleteFiles: false, - addNetImportExclusion: false + addImportExclusion: false }; } @@ -35,16 +35,16 @@ class DeleteMovieModalContent extends Component { this.setState({ deleteFiles: value }); } - onAddNetImportExclusionChange = ({ value }) => { - this.setState({ addNetImportExclusion: value }); + onAddImportExclusionChange = ({ value }) => { + this.setState({ addImportExclusion: value }); } onDeleteMovieConfirmed = () => { const deleteFiles = this.state.deleteFiles; - const addNetImportExclusion = this.state.addNetImportExclusion; + const addImportExclusion = this.state.addImportExclusion; - this.setState({ deleteFiles: false, addNetImportExclusion: false }); - this.props.onDeletePress(deleteFiles, addNetImportExclusion); + this.setState({ deleteFiles: false, addImportExclusion: false }); + this.props.onDeletePress(deleteFiles, addImportExclusion); } // @@ -64,7 +64,7 @@ class DeleteMovieModalContent extends Component { } = statistics; const deleteFiles = this.state.deleteFiles; - const addNetImportExclusion = this.state.addNetImportExclusion; + const addImportExclusion = this.state.addImportExclusion; let deleteFilesLabel = `Delete ${movieFileCount} Movie Files`; let deleteFilesHelpText = 'Delete the movie files and movie folder'; @@ -122,11 +122,11 @@ class DeleteMovieModalContent extends Component { diff --git a/frontend/src/Movie/Delete/DeleteMovieModalContentConnector.js b/frontend/src/Movie/Delete/DeleteMovieModalContentConnector.js index dcb68be20..8aef87c2b 100644 --- a/frontend/src/Movie/Delete/DeleteMovieModalContentConnector.js +++ b/frontend/src/Movie/Delete/DeleteMovieModalContentConnector.js @@ -24,11 +24,11 @@ class DeleteMovieModalContentConnector extends Component { // // Listeners - onDeletePress = (deleteFiles, addNetImportExclusion) => { + onDeletePress = (deleteFiles, addImportExclusion) => { this.props.deleteMovie({ id: this.props.movieId, deleteFiles, - addNetImportExclusion + addImportExclusion }); this.props.onModalClose(true); diff --git a/frontend/src/Movie/Details/Credits/Cast/MovieCastPoster.js b/frontend/src/Movie/Details/Credits/Cast/MovieCastPoster.js index dfce45d39..90b409b31 100644 --- a/frontend/src/Movie/Details/Credits/Cast/MovieCastPoster.js +++ b/frontend/src/Movie/Details/Credits/Cast/MovieCastPoster.js @@ -4,7 +4,7 @@ import Label from 'Components/Label'; import IconButton from 'Components/Link/IconButton'; import { icons } from 'Helpers/Props'; import MovieHeadshot from 'Movie/MovieHeadshot'; -import EditNetImportModalConnector from 'Settings/NetImport/NetImport/EditNetImportModalConnector'; +import EditImportListModalConnector from 'Settings/ImportLists/ImportLists/EditImportListModalConnector'; import translate from 'Utilities/String/translate'; import styles from '../MovieCreditPoster.css'; @@ -18,24 +18,24 @@ class MovieCastPoster extends Component { this.state = { hasPosterError: false, - isEditNetImportModalOpen: false + isEditImportListModalOpen: false }; } // // Listeners - onEditNetImportPress = () => { - this.setState({ isEditNetImportModalOpen: true }); + onEditImportListPress = () => { + this.setState({ isEditImportListModalOpen: true }); } - onAddNetImportPress = () => { - this.props.onNetImportSelect(); - this.setState({ isEditNetImportModalOpen: true }); + onAddImportListPress = () => { + this.props.onImportListSelect(); + this.setState({ isEditImportListModalOpen: true }); } - onEditNetImportModalClose = () => { - this.setState({ isEditNetImportModalOpen: false }); + onEditImportListModalClose = () => { + this.setState({ isEditImportListModalOpen: false }); } onPosterLoad = () => { @@ -60,7 +60,7 @@ class MovieCastPoster extends Component { images, posterWidth, posterHeight, - netImportId + importListId } = this.props; const { @@ -84,18 +84,18 @@ class MovieCastPoster extends Component {
@@ -130,11 +130,11 @@ class MovieCastPoster extends Component { {character}
- ); @@ -148,12 +148,12 @@ MovieCastPoster.propTypes = { images: PropTypes.arrayOf(PropTypes.object).isRequired, posterWidth: PropTypes.number.isRequired, posterHeight: PropTypes.number.isRequired, - netImportId: PropTypes.number.isRequired, - onNetImportSelect: PropTypes.func.isRequired + importListId: PropTypes.number.isRequired, + onImportListSelect: PropTypes.func.isRequired }; MovieCastPoster.defaultProps = { - netImportId: 0 + importListId: 0 }; export default MovieCastPoster; diff --git a/frontend/src/Movie/Details/Credits/Crew/MovieCrewPoster.js b/frontend/src/Movie/Details/Credits/Crew/MovieCrewPoster.js index 56d5a93b8..70ce32984 100644 --- a/frontend/src/Movie/Details/Credits/Crew/MovieCrewPoster.js +++ b/frontend/src/Movie/Details/Credits/Crew/MovieCrewPoster.js @@ -4,7 +4,7 @@ import Label from 'Components/Label'; import IconButton from 'Components/Link/IconButton'; import { icons } from 'Helpers/Props'; import MovieHeadshot from 'Movie/MovieHeadshot'; -import EditNetImportModalConnector from 'Settings/NetImport/NetImport/EditNetImportModalConnector'; +import EditImportListModalConnector from 'Settings/ImportLists/ImportLists/EditImportListModalConnector'; import translate from 'Utilities/String/translate'; import styles from '../MovieCreditPoster.css'; @@ -18,24 +18,24 @@ class MovieCrewPoster extends Component { this.state = { hasPosterError: false, - isEditNetImportModalOpen: false + isEditImportListModalOpen: false }; } // // Listeners - onEditNetImportPress = () => { - this.setState({ isEditNetImportModalOpen: true }); + onEditImportListPress = () => { + this.setState({ isEditImportListModalOpen: true }); } - onAddNetImportPress = () => { - this.props.onNetImportSelect(); - this.setState({ isEditNetImportModalOpen: true }); + onAddImportListPress = () => { + this.props.onImportListSelect(); + this.setState({ isEditImportListModalOpen: true }); } - onEditNetImportModalClose = () => { - this.setState({ isEditNetImportModalOpen: false }); + onEditImportListModalClose = () => { + this.setState({ isEditImportListModalOpen: false }); } onPosterLoad = () => { @@ -60,7 +60,7 @@ class MovieCrewPoster extends Component { images, posterWidth, posterHeight, - netImportId + importListId } = this.props; const { @@ -84,18 +84,18 @@ class MovieCrewPoster extends Component {
@@ -130,11 +130,11 @@ class MovieCrewPoster extends Component { {job}
- ); @@ -148,12 +148,12 @@ MovieCrewPoster.propTypes = { images: PropTypes.arrayOf(PropTypes.object).isRequired, posterWidth: PropTypes.number.isRequired, posterHeight: PropTypes.number.isRequired, - netImportId: PropTypes.number.isRequired, - onNetImportSelect: PropTypes.func.isRequired + importListId: PropTypes.number.isRequired, + onImportListSelect: PropTypes.func.isRequired }; MovieCrewPoster.defaultProps = { - netImportId: 0 + importListId: 0 }; export default MovieCrewPoster; diff --git a/frontend/src/Movie/Details/Credits/MovieCreditPosterConnector.js b/frontend/src/Movie/Details/Credits/MovieCreditPosterConnector.js index 4a280dd70..e58741666 100644 --- a/frontend/src/Movie/Details/Credits/MovieCreditPosterConnector.js +++ b/frontend/src/Movie/Details/Credits/MovieCreditPosterConnector.js @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; -import { selectNetImportSchema, setNetImportFieldValue, setNetImportValue } from 'Store/Actions/settingsActions'; +import { selectImportListSchema, setImportListFieldValue, setImportListValue } from 'Store/Actions/settingsActions'; import createMovieCreditListSelector from 'Store/Selectors/createMovieCreditListSelector'; function createMapStateToProps() { @@ -9,9 +9,9 @@ function createMapStateToProps() { } const mapDispatchToProps = { - selectNetImportSchema, - setNetImportFieldValue, - setNetImportValue + selectImportListSchema, + setImportListFieldValue, + setImportListValue }; class MovieCreditPosterConnector extends Component { @@ -19,10 +19,10 @@ class MovieCreditPosterConnector extends Component { // // Listeners - onNetImportSelect = () => { - this.props.selectNetImportSchema({ implementation: 'TMDbPersonImport', presetName: undefined }); - this.props.setNetImportFieldValue({ name: 'personId', value: this.props.tmdbId.toString() }); - this.props.setNetImportValue({ name: 'name', value: `${this.props.personName} - ${this.props.tmdbId}` }); + onImportListSelect = () => { + this.props.selectImportListSchema({ implementation: 'TMDbPersonImport', presetName: undefined }); + this.props.setImportListFieldValue({ name: 'personId', value: this.props.tmdbId.toString() }); + this.props.setImportListValue({ name: 'name', value: `${this.props.personName} - ${this.props.tmdbId}` }); } // @@ -40,7 +40,7 @@ class MovieCreditPosterConnector extends Component { {...this.props} tmdbId={tmdbId} personName={personName} - onNetImportSelect={this.onNetImportSelect} + onImportListSelect={this.onImportListSelect} /> ); } @@ -50,9 +50,9 @@ MovieCreditPosterConnector.propTypes = { tmdbId: PropTypes.number.isRequired, personName: PropTypes.string.isRequired, component: PropTypes.elementType.isRequired, - selectNetImportSchema: PropTypes.func.isRequired, - setNetImportFieldValue: PropTypes.func.isRequired, - setNetImportValue: PropTypes.func.isRequired + selectImportListSchema: PropTypes.func.isRequired, + setImportListFieldValue: PropTypes.func.isRequired, + setImportListValue: PropTypes.func.isRequired }; export default connect(createMapStateToProps, mapDispatchToProps)(MovieCreditPosterConnector); diff --git a/frontend/src/Movie/Details/MovieDetailsConnector.js b/frontend/src/Movie/Details/MovieDetailsConnector.js index e5679f8ae..207e39728 100644 --- a/frontend/src/Movie/Details/MovieDetailsConnector.js +++ b/frontend/src/Movie/Details/MovieDetailsConnector.js @@ -12,7 +12,7 @@ import { clearMovieCredits, fetchMovieCredits } from 'Store/Actions/movieCredits import { clearMovieFiles, fetchMovieFiles } from 'Store/Actions/movieFileActions'; import { clearQueueDetails, fetchQueueDetails } from 'Store/Actions/queueActions'; import { cancelFetchReleases, clearReleases } from 'Store/Actions/releaseActions'; -import { fetchNetImportSchema } from 'Store/Actions/settingsActions'; +import { fetchImportListSchema } from 'Store/Actions/settingsActions'; import createAllMoviesSelector from 'Store/Selectors/createAllMoviesSelector'; import createCommandsSelector from 'Store/Selectors/createCommandsSelector'; import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector'; @@ -198,8 +198,8 @@ function createMapDispatchToProps(dispatch, props) { dispatchClearQueueDetails() { dispatch(clearQueueDetails()); }, - dispatchFetchNetImportSchema() { - dispatch(fetchNetImportSchema()); + dispatchFetchImportListSchema() { + dispatch(fetchImportListSchema()); }, dispatchToggleMovieMonitored(payload) { dispatch(toggleMovieMonitored(payload)); @@ -265,7 +265,7 @@ class MovieDetailsConnector extends Component { this.props.dispatchFetchExtraFiles({ movieId }); this.props.dispatchFetchMovieCredits({ movieId }); this.props.dispatchFetchQueueDetails({ movieId }); - this.props.dispatchFetchNetImportSchema(); + this.props.dispatchFetchImportListSchema(); } unpopulate = () => { @@ -336,7 +336,7 @@ MovieDetailsConnector.propTypes = { dispatchToggleMovieMonitored: PropTypes.func.isRequired, dispatchFetchQueueDetails: PropTypes.func.isRequired, dispatchClearQueueDetails: PropTypes.func.isRequired, - dispatchFetchNetImportSchema: PropTypes.func.isRequired, + dispatchFetchImportListSchema: PropTypes.func.isRequired, dispatchExecuteCommand: PropTypes.func.isRequired, onGoToMovie: PropTypes.func.isRequired }; diff --git a/frontend/src/Movie/Editor/Delete/DeleteMovieModalContent.js b/frontend/src/Movie/Editor/Delete/DeleteMovieModalContent.js index 6d63202ec..eeb434789 100644 --- a/frontend/src/Movie/Editor/Delete/DeleteMovieModalContent.js +++ b/frontend/src/Movie/Editor/Delete/DeleteMovieModalContent.js @@ -22,7 +22,7 @@ class DeleteMovieModalContent extends Component { this.state = { deleteFiles: false, - addNetImportExclusion: false + addImportExclusion: false }; } @@ -33,16 +33,16 @@ class DeleteMovieModalContent extends Component { this.setState({ deleteFiles: value }); } - onAddNetImportExclusionChange = ({ value }) => { - this.setState({ addNetImportExclusion: value }); + onAddImportExclusionChange = ({ value }) => { + this.setState({ addImportExclusion: value }); } onDeleteMovieConfirmed = () => { const deleteFiles = this.state.deleteFiles; - const addNetImportExclusion = this.state.addNetImportExclusion; + const addImportExclusion = this.state.addImportExclusion; - this.setState({ deleteFiles: false, addNetImportExclusion: false }); - this.props.onDeleteSelectedPress(deleteFiles, addNetImportExclusion); + this.setState({ deleteFiles: false, addImportExclusion: false }); + this.props.onDeleteSelectedPress(deleteFiles, addImportExclusion); } // @@ -55,7 +55,7 @@ class DeleteMovieModalContent extends Component { } = this.props; const deleteFiles = this.state.deleteFiles; - const addNetImportExclusion = this.state.addNetImportExclusion; + const addImportExclusion = this.state.addImportExclusion; return ( @@ -83,11 +83,11 @@ class DeleteMovieModalContent extends Component { diff --git a/frontend/src/Movie/Editor/Delete/DeleteMovieModalContentConnector.js b/frontend/src/Movie/Editor/Delete/DeleteMovieModalContentConnector.js index 493f158c8..d3d26105b 100644 --- a/frontend/src/Movie/Editor/Delete/DeleteMovieModalContentConnector.js +++ b/frontend/src/Movie/Editor/Delete/DeleteMovieModalContentConnector.js @@ -31,11 +31,11 @@ function createMapStateToProps() { function createMapDispatchToProps(dispatch, props) { return { - onDeleteSelectedPress(deleteFiles, addNetImportExclusion) { + onDeleteSelectedPress(deleteFiles, addImportExclusion) { dispatch(bulkDeleteMovie({ movieIds: props.movieIds, deleteFiles, - addNetImportExclusion + addImportExclusion })); props.onModalClose(); diff --git a/frontend/src/Movie/MovieCollection.js b/frontend/src/Movie/MovieCollection.js index 09a8eea73..396638ec9 100644 --- a/frontend/src/Movie/MovieCollection.js +++ b/frontend/src/Movie/MovieCollection.js @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import MonitorToggleButton from 'Components/MonitorToggleButton'; -import EditNetImportModalConnector from 'Settings/NetImport/NetImport/EditNetImportModalConnector'; +import EditImportListModalConnector from 'Settings/ImportLists/ImportLists/EditImportListModalConnector'; import styles from './MovieCollection.css'; class MovieCollection extends Component { @@ -14,21 +14,21 @@ class MovieCollection extends Component { this.state = { hasPosterError: false, - isEditNetImportModalOpen: false + isEditImportListModalOpen: false }; } - onAddNetImportPress = (monitored) => { + onAddImportListPress = (monitored) => { if (this.props.collectionList) { this.props.onMonitorTogglePress(monitored); } else { this.props.onMonitorTogglePress(monitored); - this.setState({ isEditNetImportModalOpen: true }); + this.setState({ isEditImportListModalOpen: true }); } } - onEditNetImportModalClose = () => { - this.setState({ isEditNetImportModalOpen: false }); + onEditImportListModalClose = () => { + this.setState({ isEditImportListModalOpen: false }); } render() { @@ -39,7 +39,7 @@ class MovieCollection extends Component { } = this.props; const monitored = collectionList !== undefined && collectionList.enabled && collectionList.enableAuto; - const netImportId = collectionList ? collectionList.id : 0; + const importListId = collectionList ? collectionList.id : 0; return (
@@ -48,14 +48,14 @@ class MovieCollection extends Component { monitored={monitored} isSaving={isSaving} size={15} - onPress={this.onAddNetImportPress} + onPress={this.onAddImportListPress} /> {name} -
); diff --git a/frontend/src/Movie/MovieCollectionConnector.js b/frontend/src/Movie/MovieCollectionConnector.js index 2cc5ec7a3..3b119d14a 100644 --- a/frontend/src/Movie/MovieCollectionConnector.js +++ b/frontend/src/Movie/MovieCollectionConnector.js @@ -2,7 +2,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { saveNetImport, selectNetImportSchema, setNetImportFieldValue, setNetImportValue } from 'Store/Actions/settingsActions'; +import { saveImportList, selectImportListSchema, setImportListFieldValue, setImportListValue } from 'Store/Actions/settingsActions'; import createMovieCollectionListSelector from 'Store/Selectors/createMovieCollectionListSelector'; import createMovieSelector from 'Store/Selectors/createMovieSelector'; import MovieCollection from './MovieCollection'; @@ -11,8 +11,8 @@ function createMapStateToProps() { return createSelector( createMovieSelector(), createMovieCollectionListSelector(), - (state) => state.settings.netImports, - (movie, collectionList, netImports) => { + (state) => state.settings.importLists, + (movie, collectionList, importLists) => { const { monitored, qualityProfileId, @@ -24,17 +24,17 @@ function createMapStateToProps() { monitored, qualityProfileId, minimumAvailability, - isSaving: netImports.isSaving + isSaving: importLists.isSaving }; } ); } const mapDispatchToProps = { - selectNetImportSchema, - setNetImportFieldValue, - setNetImportValue, - saveNetImport + selectImportListSchema, + setImportListFieldValue, + setImportListValue, + saveImportList }; class MovieCollectionConnector extends Component { @@ -44,18 +44,18 @@ class MovieCollectionConnector extends Component { onMonitorTogglePress = (monitored) => { if (this.props.collectionList) { - this.props.setNetImportValue({ name: 'enabled', value: monitored }); - this.props.setNetImportValue({ name: 'enableAuto', value: monitored }); - this.props.saveNetImport({ id: this.props.collectionList.id }); + this.props.setImportListValue({ name: 'enabled', value: monitored }); + this.props.setImportListValue({ name: 'enableAuto', value: monitored }); + this.props.saveImportList({ id: this.props.collectionList.id }); } else { - this.props.selectNetImportSchema({ implementation: 'TMDbCollectionImport', presetName: undefined }); - this.props.setNetImportFieldValue({ name: 'collectionId', value: this.props.tmdbId.toString() }); - this.props.setNetImportValue({ name: 'enabled', value: true }); - this.props.setNetImportValue({ name: 'enableAuto', value: true }); - this.props.setNetImportValue({ name: 'name', value: `${this.props.name} - ${this.props.tmdbId}` }); - this.props.setNetImportValue({ name: 'qualityProfileId', value: this.props.qualityProfileId }); - this.props.setNetImportValue({ name: 'monitored', value: this.props.monitored }); - this.props.setNetImportValue({ name: 'minimumAvailability', value: this.props.minimumAvailability }); + this.props.selectImportListSchema({ implementation: 'TMDbCollectionImport', presetName: undefined }); + this.props.setImportListFieldValue({ name: 'collectionId', value: this.props.tmdbId.toString() }); + this.props.setImportListValue({ name: 'enabled', value: true }); + this.props.setImportListValue({ name: 'enableAuto', value: true }); + this.props.setImportListValue({ name: 'name', value: `${this.props.name} - ${this.props.tmdbId}` }); + this.props.setImportListValue({ name: 'qualityProfileId', value: this.props.qualityProfileId }); + this.props.setImportListValue({ name: 'monitored', value: this.props.monitored }); + this.props.setImportListValue({ name: 'minimumAvailability', value: this.props.minimumAvailability }); } } @@ -81,10 +81,10 @@ MovieCollectionConnector.propTypes = { qualityProfileId: PropTypes.number.isRequired, minimumAvailability: PropTypes.string.isRequired, isSaving: PropTypes.bool.isRequired, - selectNetImportSchema: PropTypes.func.isRequired, - setNetImportFieldValue: PropTypes.func.isRequired, - setNetImportValue: PropTypes.func.isRequired, - saveNetImport: PropTypes.func.isRequired + selectImportListSchema: PropTypes.func.isRequired, + setImportListFieldValue: PropTypes.func.isRequired, + setImportListValue: PropTypes.func.isRequired, + saveImportList: PropTypes.func.isRequired }; export default connect(createMapStateToProps, mapDispatchToProps)(MovieCollectionConnector); diff --git a/frontend/src/Settings/NetImport/NetImportExclusions/EditNetImportExclusionModal.js b/frontend/src/Settings/ImportLists/ImportExclusions/EditImportExclusionModal.js similarity index 57% rename from frontend/src/Settings/NetImport/NetImportExclusions/EditNetImportExclusionModal.js rename to frontend/src/Settings/ImportLists/ImportExclusions/EditImportExclusionModal.js index 3a8d8bd94..9d140de43 100644 --- a/frontend/src/Settings/NetImport/NetImportExclusions/EditNetImportExclusionModal.js +++ b/frontend/src/Settings/ImportLists/ImportExclusions/EditImportExclusionModal.js @@ -2,16 +2,16 @@ import PropTypes from 'prop-types'; import React from 'react'; import Modal from 'Components/Modal/Modal'; import { sizes } from 'Helpers/Props'; -import EditNetImportExclusionModalContentConnector from './EditNetImportExclusionModalContentConnector'; +import EditImportExclusionModalContentConnector from './EditImportExclusionModalContentConnector'; -function EditNetImportExclusionModal({ isOpen, onModalClose, ...otherProps }) { +function EditImportExclusionModal({ isOpen, onModalClose, ...otherProps }) { return ( - @@ -19,9 +19,9 @@ function EditNetImportExclusionModal({ isOpen, onModalClose, ...otherProps }) { ); } -EditNetImportExclusionModal.propTypes = { +EditImportExclusionModal.propTypes = { isOpen: PropTypes.bool.isRequired, onModalClose: PropTypes.func.isRequired }; -export default EditNetImportExclusionModal; +export default EditImportExclusionModal; diff --git a/frontend/src/Settings/NetImport/NetImportExclusions/EditNetImportExclusionModalConnector.js b/frontend/src/Settings/ImportLists/ImportExclusions/EditImportExclusionModalConnector.js similarity index 66% rename from frontend/src/Settings/NetImport/NetImportExclusions/EditNetImportExclusionModalConnector.js rename to frontend/src/Settings/ImportLists/ImportExclusions/EditImportExclusionModalConnector.js index 3d5833f8e..f7e6dee80 100644 --- a/frontend/src/Settings/NetImport/NetImportExclusions/EditNetImportExclusionModalConnector.js +++ b/frontend/src/Settings/ImportLists/ImportExclusions/EditImportExclusionModalConnector.js @@ -2,7 +2,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; import { clearPendingChanges } from 'Store/Actions/baseActions'; -import EditNetImportExclusionModal from './EditNetImportExclusionModal'; +import EditImportExclusionModal from './EditImportExclusionModal'; function mapStateToProps() { return {}; @@ -12,13 +12,13 @@ const mapDispatchToProps = { clearPendingChanges }; -class EditNetImportExclusionModalConnector extends Component { +class EditImportExclusionModalConnector extends Component { // // Listeners onModalClose = () => { - this.props.clearPendingChanges({ section: 'settings.netImportExclusions' }); + this.props.clearPendingChanges({ section: 'settings.importExclusions' }); this.props.onModalClose(); } @@ -27,7 +27,7 @@ class EditNetImportExclusionModalConnector extends Component { render() { return ( - @@ -35,9 +35,9 @@ class EditNetImportExclusionModalConnector extends Component { } } -EditNetImportExclusionModalConnector.propTypes = { +EditImportExclusionModalConnector.propTypes = { onModalClose: PropTypes.func.isRequired, clearPendingChanges: PropTypes.func.isRequired }; -export default connect(mapStateToProps, mapDispatchToProps)(EditNetImportExclusionModalConnector); +export default connect(mapStateToProps, mapDispatchToProps)(EditImportExclusionModalConnector); diff --git a/frontend/src/Settings/NetImport/NetImportExclusions/EditNetImportExclusionModalContent.css b/frontend/src/Settings/ImportLists/ImportExclusions/EditImportExclusionModalContent.css similarity index 100% rename from frontend/src/Settings/NetImport/NetImportExclusions/EditNetImportExclusionModalContent.css rename to frontend/src/Settings/ImportLists/ImportExclusions/EditImportExclusionModalContent.css diff --git a/frontend/src/Settings/NetImport/NetImportExclusions/EditNetImportExclusionModalContent.js b/frontend/src/Settings/ImportLists/ImportExclusions/EditImportExclusionModalContent.js similarity index 91% rename from frontend/src/Settings/NetImport/NetImportExclusions/EditNetImportExclusionModalContent.js rename to frontend/src/Settings/ImportLists/ImportExclusions/EditImportExclusionModalContent.js index 7fbe22b82..36743e6e2 100644 --- a/frontend/src/Settings/NetImport/NetImportExclusions/EditNetImportExclusionModalContent.js +++ b/frontend/src/Settings/ImportLists/ImportExclusions/EditImportExclusionModalContent.js @@ -13,9 +13,9 @@ import ModalFooter from 'Components/Modal/ModalFooter'; import ModalHeader from 'Components/Modal/ModalHeader'; import { inputTypes, kinds } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; -import styles from './EditNetImportExclusionModalContent.css'; +import styles from './EditImportExclusionModalContent.css'; -function EditNetImportExclusionModalContent(props) { +function EditImportExclusionModalContent(props) { const { id, isFetching, @@ -26,7 +26,7 @@ function EditNetImportExclusionModalContent(props) { onInputChange, onSavePress, onModalClose, - onDeleteNetImportExclusionPress, + onDeleteImportExclusionPress, ...otherProps } = props; @@ -104,7 +104,7 @@ function EditNetImportExclusionModalContent(props) { @@ -128,7 +128,7 @@ function EditNetImportExclusionModalContent(props) { ); } -EditNetImportExclusionModalContent.propTypes = { +EditImportExclusionModalContent.propTypes = { id: PropTypes.number, isFetching: PropTypes.bool.isRequired, error: PropTypes.object, @@ -138,7 +138,7 @@ EditNetImportExclusionModalContent.propTypes = { onInputChange: PropTypes.func.isRequired, onSavePress: PropTypes.func.isRequired, onModalClose: PropTypes.func.isRequired, - onDeleteNetImportExclusionPress: PropTypes.func + onDeleteImportExclusionPress: PropTypes.func }; -export default EditNetImportExclusionModalContent; +export default EditImportExclusionModalContent; diff --git a/frontend/src/Settings/NetImport/NetImportExclusions/EditNetImportExclusionModalContentConnector.js b/frontend/src/Settings/ImportLists/ImportExclusions/EditImportExclusionModalContentConnector.js similarity index 57% rename from frontend/src/Settings/NetImport/NetImportExclusions/EditNetImportExclusionModalContentConnector.js rename to frontend/src/Settings/ImportLists/ImportExclusions/EditImportExclusionModalContentConnector.js index 3a515e20f..70ea1d873 100644 --- a/frontend/src/Settings/NetImport/NetImportExclusions/EditNetImportExclusionModalContentConnector.js +++ b/frontend/src/Settings/ImportLists/ImportExclusions/EditImportExclusionModalContentConnector.js @@ -3,21 +3,21 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { saveNetImportExclusion, setNetImportExclusionValue } from 'Store/Actions/settingsActions'; +import { saveImportExclusion, setImportExclusionValue } from 'Store/Actions/settingsActions'; import selectSettings from 'Store/Selectors/selectSettings'; -import EditNetImportExclusionModalContent from './EditNetImportExclusionModalContent'; +import EditImportExclusionModalContent from './EditImportExclusionModalContent'; -const newNetImportExclusion = { +const newImportExclusion = { movieTitle: '', tmdbId: 0, movieYear: 0 }; -function createNetImportExclusionSelector() { +function createImportExclusionSelector() { return createSelector( (state, { id }) => id, - (state) => state.settings.netImportExclusions, - (id, netImportExclusions) => { + (state) => state.settings.importExclusions, + (id, importExclusions) => { const { isFetching, error, @@ -25,9 +25,9 @@ function createNetImportExclusionSelector() { saveError, pendingChanges, items - } = netImportExclusions; + } = importExclusions; - const mapping = id ? _.find(items, { id }) : newNetImportExclusion; + const mapping = id ? _.find(items, { id }) : newImportExclusion; const settings = selectSettings(mapping, pendingChanges, saveError); return { @@ -45,31 +45,31 @@ function createNetImportExclusionSelector() { function createMapStateToProps() { return createSelector( - createNetImportExclusionSelector(), - (netImportExclusion) => { + createImportExclusionSelector(), + (importExclusion) => { return { - ...netImportExclusion + ...importExclusion }; } ); } const mapDispatchToProps = { - setNetImportExclusionValue, - saveNetImportExclusion + setImportExclusionValue, + saveImportExclusion }; -class EditNetImportExclusionModalContentConnector extends Component { +class EditImportExclusionModalContentConnector extends Component { // // Lifecycle componentDidMount() { if (!this.props.id) { - Object.keys(newNetImportExclusion).forEach((name) => { - this.props.setNetImportExclusionValue({ + Object.keys(newImportExclusion).forEach((name) => { + this.props.setImportExclusionValue({ name, - value: newNetImportExclusion[name] + value: newImportExclusion[name] }); }); } @@ -85,11 +85,11 @@ class EditNetImportExclusionModalContentConnector extends Component { // Listeners onInputChange = ({ name, value }) => { - this.props.setNetImportExclusionValue({ name, value }); + this.props.setImportExclusionValue({ name, value }); } onSavePress = () => { - this.props.saveNetImportExclusion({ id: this.props.id }); + this.props.saveImportExclusion({ id: this.props.id }); } // @@ -97,7 +97,7 @@ class EditNetImportExclusionModalContentConnector extends Component { render() { return ( - { - this.setState({ isEditNetImportExclusionModalOpen: true }); + onEditImportExclusionPress = () => { + this.setState({ isEditImportExclusionModalOpen: true }); } - onEditNetImportExclusionModalClose = () => { - this.setState({ isEditNetImportExclusionModalOpen: false }); + onEditImportExclusionModalClose = () => { + this.setState({ isEditImportExclusionModalOpen: false }); } - onDeleteNetImportExclusionPress = () => { + onDeleteImportExclusionPress = () => { this.setState({ - isEditNetImportExclusionModalOpen: false, - isDeleteNetImportExclusionModalOpen: true + isEditImportExclusionModalOpen: false, + isDeleteImportExclusionModalOpen: true }); } - onDeleteNetImportExclusionModalClose = () => { - this.setState({ isDeleteNetImportExclusionModalOpen: false }); + onDeleteImportExclusionModalClose = () => { + this.setState({ isDeleteImportExclusionModalOpen: false }); } - onConfirmDeleteNetImportExclusion = () => { - this.props.onConfirmDeleteNetImportExclusion(this.props.id); + onConfirmDeleteImportExclusion = () => { + this.props.onConfirmDeleteImportExclusion(this.props.id); } // @@ -63,7 +63,7 @@ class NetImportExclusion extends Component { return (
{tmdbId}
@@ -72,44 +72,44 @@ class NetImportExclusion extends Component {
-
); } } -NetImportExclusion.propTypes = { +ImportExclusion.propTypes = { id: PropTypes.number.isRequired, movieTitle: PropTypes.string.isRequired, tmdbId: PropTypes.number.isRequired, movieYear: PropTypes.number.isRequired, - onConfirmDeleteNetImportExclusion: PropTypes.func.isRequired + onConfirmDeleteImportExclusion: PropTypes.func.isRequired }; -NetImportExclusion.defaultProps = { +ImportExclusion.defaultProps = { // The drag preview will not connect the drag handle. connectDragSource: (node) => node }; -export default NetImportExclusion; +export default ImportExclusion; diff --git a/frontend/src/Settings/NetImport/NetImportExclusions/NetImportExclusions.css b/frontend/src/Settings/ImportLists/ImportExclusions/ImportExclusions.css similarity index 82% rename from frontend/src/Settings/NetImport/NetImportExclusions/NetImportExclusions.css rename to frontend/src/Settings/ImportLists/ImportExclusions/ImportExclusions.css index 00b917a84..06720845c 100644 --- a/frontend/src/Settings/NetImport/NetImportExclusions/NetImportExclusions.css +++ b/frontend/src/Settings/ImportLists/ImportExclusions/ImportExclusions.css @@ -1,4 +1,4 @@ -.netImportExclusionsHeader { +.importExclusionsHeader { display: flex; margin-bottom: 10px; font-weight: bold; @@ -13,7 +13,7 @@ flex: 0 0 200px; } -.addNetImportExclusion { +.addImportExclusion { display: flex; justify-content: flex-end; padding-right: 10px; diff --git a/frontend/src/Settings/NetImport/NetImportExclusions/NetImportExclusions.js b/frontend/src/Settings/ImportLists/ImportExclusions/ImportExclusions.js similarity index 62% rename from frontend/src/Settings/NetImport/NetImportExclusions/NetImportExclusions.js rename to frontend/src/Settings/ImportLists/ImportExclusions/ImportExclusions.js index 9f0591ed8..d2ec7acfd 100644 --- a/frontend/src/Settings/NetImport/NetImportExclusions/NetImportExclusions.js +++ b/frontend/src/Settings/ImportLists/ImportExclusions/ImportExclusions.js @@ -6,11 +6,11 @@ import Link from 'Components/Link/Link'; import PageSectionContent from 'Components/Page/PageSectionContent'; import { icons } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; -import EditNetImportExclusionModalConnector from './EditNetImportExclusionModalConnector'; -import NetImportExclusion from './NetImportExclusion'; -import styles from './NetImportExclusions.css'; +import EditImportExclusionModalConnector from './EditImportExclusionModalConnector'; +import ImportExclusion from './ImportExclusion'; +import styles from './ImportExclusions.css'; -class NetImportExclusions extends Component { +class ImportExclusions extends Component { // // Lifecycle @@ -19,19 +19,19 @@ class NetImportExclusions extends Component { super(props, context); this.state = { - isAddNetImportExclusionModalOpen: false + isAddImportExclusionModalOpen: false }; } // // Listeners - onAddNetImportExclusionPress = () => { - this.setState({ isAddNetImportExclusionModalOpen: true }); + onAddImportExclusionPress = () => { + this.setState({ isAddImportExclusionModalOpen: true }); } onModalClose = () => { - this.setState({ isAddNetImportExclusionModalOpen: false }); + this.setState({ isAddImportExclusionModalOpen: false }); } // @@ -40,7 +40,7 @@ class NetImportExclusions extends Component { render() { const { items, - onConfirmDeleteNetImportExclusion, + onConfirmDeleteImportExclusion, ...otherProps } = this.props; @@ -50,7 +50,7 @@ class NetImportExclusions extends Component { errorMessage={translate('UnableToLoadListExclusions')} {...otherProps} > -
+
TMDB Id
Title
Year
@@ -60,29 +60,29 @@ class NetImportExclusions extends Component { { items.map((item, index) => { return ( - ); }) }
-
+
- @@ -92,11 +92,11 @@ class NetImportExclusions extends Component { } } -NetImportExclusions.propTypes = { +ImportExclusions.propTypes = { isFetching: PropTypes.bool.isRequired, error: PropTypes.object, items: PropTypes.arrayOf(PropTypes.object).isRequired, - onConfirmDeleteNetImportExclusion: PropTypes.func.isRequired + onConfirmDeleteImportExclusion: PropTypes.func.isRequired }; -export default NetImportExclusions; +export default ImportExclusions; diff --git a/frontend/src/Settings/ImportLists/ImportExclusions/ImportExclusionsConnector.js b/frontend/src/Settings/ImportLists/ImportExclusions/ImportExclusionsConnector.js new file mode 100644 index 000000000..4cf7320a8 --- /dev/null +++ b/frontend/src/Settings/ImportLists/ImportExclusions/ImportExclusionsConnector.js @@ -0,0 +1,59 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import { deleteImportExclusion, fetchImportExclusions } from 'Store/Actions/settingsActions'; +import ImportExclusions from './ImportExclusions'; + +function createMapStateToProps() { + return createSelector( + (state) => state.settings.importExclusions, + (importExclusions) => { + return { + ...importExclusions + }; + } + ); +} + +const mapDispatchToProps = { + fetchImportExclusions, + deleteImportExclusion +}; + +class ImportExclusionsConnector extends Component { + + // + // Lifecycle + + componentDidMount() { + this.props.fetchImportExclusions(); + } + + // + // Listeners + + onConfirmDeleteImportExclusion = (id) => { + this.props.deleteImportExclusion({ id }); + } + + // + // Render + + render() { + return ( + + ); + } +} + +ImportExclusionsConnector.propTypes = { + fetchImportExclusions: PropTypes.func.isRequired, + deleteImportExclusion: PropTypes.func.isRequired +}; + +export default connect(createMapStateToProps, mapDispatchToProps)(ImportExclusionsConnector); diff --git a/frontend/src/Settings/NetImport/NetImportSettings.js b/frontend/src/Settings/ImportLists/ImportListSettings.js similarity index 76% rename from frontend/src/Settings/NetImport/NetImportSettings.js rename to frontend/src/Settings/ImportLists/ImportListSettings.js index d63d291ea..62a96ecf9 100644 --- a/frontend/src/Settings/NetImport/NetImportSettings.js +++ b/frontend/src/Settings/ImportLists/ImportListSettings.js @@ -7,11 +7,11 @@ import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator'; import { icons } from 'Helpers/Props'; import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector'; import translate from 'Utilities/String/translate'; -import NetImportsConnector from './NetImport/NetImportsConnector'; -import NetImportExclusionsConnector from './NetImportExclusions/NetImportExclusionsConnector'; -import NetImportOptionsConnector from './Options/NetImportOptionsConnector'; +import ImportExclusionsConnector from './ImportExclusions/ImportExclusionsConnector'; +import ImportListsConnector from './ImportLists/ImportListsConnector'; +import ImportListOptionsConnector from './Options/ImportListOptionsConnector'; -class NetImportSettings extends Component { +class ImportListSettings extends Component { // // Lifecycle @@ -50,7 +50,7 @@ class NetImportSettings extends Component { render() { const { isTestingAll, - dispatchTestAllNetImport + dispatchTestAllImportList } = this.props; const { @@ -71,7 +71,7 @@ class NetImportSettings extends Component { label={translate('TestAllLists')} iconName={icons.TEST} isSpinning={isTestingAll} - onPress={dispatchTestAllNetImport} + onPress={dispatchTestAllImportList} /> } @@ -79,14 +79,14 @@ class NetImportSettings extends Component { /> - + - - + @@ -94,9 +94,9 @@ class NetImportSettings extends Component { } } -NetImportSettings.propTypes = { +ImportListSettings.propTypes = { isTestingAll: PropTypes.bool.isRequired, - dispatchTestAllNetImport: PropTypes.func.isRequired + dispatchTestAllImportList: PropTypes.func.isRequired }; -export default NetImportSettings; +export default ImportListSettings; diff --git a/frontend/src/Settings/NetImport/NetImportSettingsConnector.js b/frontend/src/Settings/ImportLists/ImportListSettingsConnector.js similarity index 56% rename from frontend/src/Settings/NetImport/NetImportSettingsConnector.js rename to frontend/src/Settings/ImportLists/ImportListSettingsConnector.js index 0484dc88f..87c856d5d 100644 --- a/frontend/src/Settings/NetImport/NetImportSettingsConnector.js +++ b/frontend/src/Settings/ImportLists/ImportListSettingsConnector.js @@ -1,11 +1,11 @@ import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { testAllNetImport } from 'Store/Actions/settingsActions'; -import NetImportSettings from './NetImportSettings'; +import { testAllImportList } from 'Store/Actions/settingsActions'; +import ImportListSettings from './ImportListSettings'; function createMapStateToProps() { return createSelector( - (state) => state.settings.netImports.isTestingAll, + (state) => state.settings.importLists.isTestingAll, (isTestingAll) => { return { isTestingAll @@ -15,7 +15,7 @@ function createMapStateToProps() { } const mapDispatchToProps = { - dispatchTestAllNetImport: testAllNetImport + dispatchTestAllImportList: testAllImportList }; -export default connect(createMapStateToProps, mapDispatchToProps)(NetImportSettings); +export default connect(createMapStateToProps, mapDispatchToProps)(ImportListSettings); diff --git a/frontend/src/Settings/NetImport/NetImport/AddNetImportItem.css b/frontend/src/Settings/ImportLists/ImportLists/AddImportListItem.css similarity index 97% rename from frontend/src/Settings/NetImport/NetImport/AddNetImportItem.css rename to frontend/src/Settings/ImportLists/ImportLists/AddImportListItem.css index 3ed6c66d9..7b0f4c58e 100644 --- a/frontend/src/Settings/NetImport/NetImport/AddNetImportItem.css +++ b/frontend/src/Settings/ImportLists/ImportLists/AddImportListItem.css @@ -1,4 +1,4 @@ -.netImport { +.importList { composes: card from '~Components/Card.css'; position: relative; diff --git a/frontend/src/Settings/NetImport/NetImport/AddNetImportItem.js b/frontend/src/Settings/ImportLists/ImportLists/AddImportListItem.js similarity index 78% rename from frontend/src/Settings/NetImport/NetImport/AddNetImportItem.js rename to frontend/src/Settings/ImportLists/ImportLists/AddImportListItem.js index 8a26e0013..bf3c418d2 100644 --- a/frontend/src/Settings/NetImport/NetImport/AddNetImportItem.js +++ b/frontend/src/Settings/ImportLists/ImportLists/AddImportListItem.js @@ -6,20 +6,20 @@ import Menu from 'Components/Menu/Menu'; import MenuContent from 'Components/Menu/MenuContent'; import { sizes } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; -import AddNetImportPresetMenuItem from './AddNetImportPresetMenuItem'; -import styles from './AddNetImportItem.css'; +import AddImportListPresetMenuItem from './AddImportListPresetMenuItem'; +import styles from './AddImportListItem.css'; -class AddNetImportItem extends Component { +class AddImportListItem extends Component { // // Listeners - onNetImportSelect = () => { + onImportListSelect = () => { const { implementation } = this.props; - this.props.onNetImportSelect({ implementation }); + this.props.onImportListSelect({ implementation }); } // @@ -31,18 +31,18 @@ class AddNetImportItem extends Component { implementationName, infoLink, presets, - onNetImportSelect + onImportListSelect } = this.props; const hasPresets = !!presets && !!presets.length; return (
@@ -56,7 +56,7 @@ class AddNetImportItem extends Component { @@ -73,11 +73,11 @@ class AddNetImportItem extends Component { { presets.map((preset) => { return ( - ); }) @@ -100,12 +100,12 @@ class AddNetImportItem extends Component { } } -AddNetImportItem.propTypes = { +AddImportListItem.propTypes = { implementation: PropTypes.string.isRequired, implementationName: PropTypes.string.isRequired, infoLink: PropTypes.string.isRequired, presets: PropTypes.arrayOf(PropTypes.object), - onNetImportSelect: PropTypes.func.isRequired + onImportListSelect: PropTypes.func.isRequired }; -export default AddNetImportItem; +export default AddImportListItem; diff --git a/frontend/src/Settings/NetImport/NetImport/AddNetImportModal.js b/frontend/src/Settings/ImportLists/ImportLists/AddImportListModal.js similarity index 57% rename from frontend/src/Settings/NetImport/NetImport/AddNetImportModal.js rename to frontend/src/Settings/ImportLists/ImportLists/AddImportListModal.js index 4f1921e5b..a188d6b4a 100644 --- a/frontend/src/Settings/NetImport/NetImport/AddNetImportModal.js +++ b/frontend/src/Settings/ImportLists/ImportLists/AddImportListModal.js @@ -1,15 +1,15 @@ import PropTypes from 'prop-types'; import React from 'react'; import Modal from 'Components/Modal/Modal'; -import AddNetImportModalContentConnector from './AddNetImportModalContentConnector'; +import AddImportListModalContentConnector from './AddImportListModalContentConnector'; -function AddNetImportModal({ isOpen, onModalClose, ...otherProps }) { +function AddImportListModal({ isOpen, onModalClose, ...otherProps }) { return ( - @@ -17,9 +17,9 @@ function AddNetImportModal({ isOpen, onModalClose, ...otherProps }) { ); } -AddNetImportModal.propTypes = { +AddImportListModal.propTypes = { isOpen: PropTypes.bool.isRequired, onModalClose: PropTypes.func.isRequired }; -export default AddNetImportModal; +export default AddImportListModal; diff --git a/frontend/src/Settings/NetImport/NetImport/AddNetImportModalContent.css b/frontend/src/Settings/ImportLists/ImportLists/AddImportListModalContent.css similarity index 81% rename from frontend/src/Settings/NetImport/NetImport/AddNetImportModalContent.css rename to frontend/src/Settings/ImportLists/ImportLists/AddImportListModalContent.css index 6f57c542e..2fa2fbe84 100644 --- a/frontend/src/Settings/NetImport/NetImport/AddNetImportModalContent.css +++ b/frontend/src/Settings/ImportLists/ImportLists/AddImportListModalContent.css @@ -1,4 +1,4 @@ -.netImports { +.importLists { display: flex; justify-content: center; flex-wrap: wrap; diff --git a/frontend/src/Settings/NetImport/NetImport/AddNetImportModalContent.js b/frontend/src/Settings/ImportLists/ImportLists/AddImportListModalContent.js similarity index 73% rename from frontend/src/Settings/NetImport/NetImport/AddNetImportModalContent.js rename to frontend/src/Settings/ImportLists/ImportLists/AddImportListModalContent.js index 4ea541d6c..4d28b0e6f 100644 --- a/frontend/src/Settings/NetImport/NetImport/AddNetImportModalContent.js +++ b/frontend/src/Settings/ImportLists/ImportLists/AddImportListModalContent.js @@ -11,10 +11,10 @@ import ModalHeader from 'Components/Modal/ModalHeader'; import { kinds } from 'Helpers/Props'; import titleCase from 'Utilities/String/titleCase'; import translate from 'Utilities/String/translate'; -import AddNetImportItem from './AddNetImportItem'; -import styles from './AddNetImportModalContent.css'; +import AddImportListItem from './AddImportListItem'; +import styles from './AddImportListModalContent.css'; -class AddNetImportModalContent extends Component { +class AddImportListModalContent extends Component { // // Render @@ -25,7 +25,7 @@ class AddNetImportModalContent extends Component { isSchemaPopulated, schemaError, listGroups, - onNetImportSelect, + onImportListSelect, onModalClose } = this.props; @@ -52,22 +52,22 @@ class AddNetImportModalContent extends Component {
Radarr supports any RSS movie lists as well as the one stated below.
-
For more information on the individual netImports, clink on the info buttons.
+
For more information on the individual importLists, clink on the info buttons.
{ Object.keys(listGroups).map((key) => { return (
-
+
{ - listGroups[key].map((netImport) => { + listGroups[key].map((importList) => { return ( - ); }) @@ -92,13 +92,13 @@ class AddNetImportModalContent extends Component { } } -AddNetImportModalContent.propTypes = { +AddImportListModalContent.propTypes = { isSchemaFetching: PropTypes.bool.isRequired, isSchemaPopulated: PropTypes.bool.isRequired, schemaError: PropTypes.object, listGroups: PropTypes.object.isRequired, - onNetImportSelect: PropTypes.func.isRequired, + onImportListSelect: PropTypes.func.isRequired, onModalClose: PropTypes.func.isRequired }; -export default AddNetImportModalContent; +export default AddImportListModalContent; diff --git a/frontend/src/Settings/NetImport/NetImport/AddNetImportModalContentConnector.js b/frontend/src/Settings/ImportLists/ImportLists/AddImportListModalContentConnector.js similarity index 51% rename from frontend/src/Settings/NetImport/NetImport/AddNetImportModalContentConnector.js rename to frontend/src/Settings/ImportLists/ImportLists/AddImportListModalContentConnector.js index b721ffda9..67b2f1da8 100644 --- a/frontend/src/Settings/NetImport/NetImport/AddNetImportModalContentConnector.js +++ b/frontend/src/Settings/ImportLists/ImportLists/AddImportListModalContentConnector.js @@ -3,19 +3,19 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { fetchNetImportSchema, selectNetImportSchema } from 'Store/Actions/settingsActions'; -import AddNetImportModalContent from './AddNetImportModalContent'; +import { fetchImportListSchema, selectImportListSchema } from 'Store/Actions/settingsActions'; +import AddImportListModalContent from './AddImportListModalContent'; function createMapStateToProps() { return createSelector( - (state) => state.settings.netImports, - (netImports) => { + (state) => state.settings.importLists, + (importLists) => { const { isSchemaFetching, isSchemaPopulated, schemaError, schema - } = netImports; + } = importLists; const listGroups = _.chain(schema) .sortBy((o) => o.listOrder) @@ -33,25 +33,25 @@ function createMapStateToProps() { } const mapDispatchToProps = { - fetchNetImportSchema, - selectNetImportSchema + fetchImportListSchema, + selectImportListSchema }; -class AddNetImportModalContentConnector extends Component { +class AddImportListModalContentConnector extends Component { // // Lifecycle componentDidMount() { - this.props.fetchNetImportSchema(); + this.props.fetchImportListSchema(); } // // Listeners - onNetImportSelect = ({ implementation, name }) => { - this.props.selectNetImportSchema({ implementation, presetName: name }); - this.props.onModalClose({ netImportSelected: true }); + onImportListSelect = ({ implementation, name }) => { + this.props.selectImportListSchema({ implementation, presetName: name }); + this.props.onModalClose({ importListSelected: true }); } // @@ -59,18 +59,18 @@ class AddNetImportModalContentConnector extends Component { render() { return ( - ); } } -AddNetImportModalContentConnector.propTypes = { - fetchNetImportSchema: PropTypes.func.isRequired, - selectNetImportSchema: PropTypes.func.isRequired, +AddImportListModalContentConnector.propTypes = { + fetchImportListSchema: PropTypes.func.isRequired, + selectImportListSchema: PropTypes.func.isRequired, onModalClose: PropTypes.func.isRequired }; -export default connect(createMapStateToProps, mapDispatchToProps)(AddNetImportModalContentConnector); +export default connect(createMapStateToProps, mapDispatchToProps)(AddImportListModalContentConnector); diff --git a/frontend/src/Settings/NetImport/NetImport/AddNetImportPresetMenuItem.js b/frontend/src/Settings/ImportLists/ImportLists/AddImportListPresetMenuItem.js similarity index 83% rename from frontend/src/Settings/NetImport/NetImport/AddNetImportPresetMenuItem.js rename to frontend/src/Settings/ImportLists/ImportLists/AddImportListPresetMenuItem.js index 75f6279cb..477044ae0 100644 --- a/frontend/src/Settings/NetImport/NetImport/AddNetImportPresetMenuItem.js +++ b/frontend/src/Settings/ImportLists/ImportLists/AddImportListPresetMenuItem.js @@ -2,7 +2,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import MenuItem from 'Components/Menu/MenuItem'; -class AddNetImportPresetMenuItem extends Component { +class AddImportListPresetMenuItem extends Component { // // Listeners @@ -40,10 +40,10 @@ class AddNetImportPresetMenuItem extends Component { } } -AddNetImportPresetMenuItem.propTypes = { +AddImportListPresetMenuItem.propTypes = { name: PropTypes.string.isRequired, implementation: PropTypes.string.isRequired, onPress: PropTypes.func.isRequired }; -export default AddNetImportPresetMenuItem; +export default AddImportListPresetMenuItem; diff --git a/frontend/src/Settings/NetImport/NetImport/EditNetImportModal.js b/frontend/src/Settings/ImportLists/ImportLists/EditImportListModal.js similarity index 61% rename from frontend/src/Settings/NetImport/NetImport/EditNetImportModal.js rename to frontend/src/Settings/ImportLists/ImportLists/EditImportListModal.js index 55badaa55..5fec8e09d 100644 --- a/frontend/src/Settings/NetImport/NetImport/EditNetImportModal.js +++ b/frontend/src/Settings/ImportLists/ImportLists/EditImportListModal.js @@ -2,16 +2,16 @@ import PropTypes from 'prop-types'; import React from 'react'; import Modal from 'Components/Modal/Modal'; import { sizes } from 'Helpers/Props'; -import EditNetImportModalContentConnector from './EditNetImportModalContentConnector'; +import EditImportListModalContentConnector from './EditImportListModalContentConnector'; -function EditNetImportModal({ isOpen, onModalClose, ...otherProps }) { +function EditImportListModal({ isOpen, onModalClose, ...otherProps }) { return ( - @@ -19,9 +19,9 @@ function EditNetImportModal({ isOpen, onModalClose, ...otherProps }) { ); } -EditNetImportModal.propTypes = { +EditImportListModal.propTypes = { isOpen: PropTypes.bool.isRequired, onModalClose: PropTypes.func.isRequired }; -export default EditNetImportModal; +export default EditImportListModal; diff --git a/frontend/src/Settings/ImportLists/ImportLists/EditImportListModalConnector.js b/frontend/src/Settings/ImportLists/ImportLists/EditImportListModalConnector.js new file mode 100644 index 000000000..b4632918b --- /dev/null +++ b/frontend/src/Settings/ImportLists/ImportLists/EditImportListModalConnector.js @@ -0,0 +1,65 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { clearPendingChanges } from 'Store/Actions/baseActions'; +import { cancelSaveImportList, cancelTestImportList } from 'Store/Actions/settingsActions'; +import EditImportListModal from './EditImportListModal'; + +function createMapDispatchToProps(dispatch, props) { + const section = 'settings.importLists'; + + return { + dispatchClearPendingChanges() { + dispatch(clearPendingChanges({ section })); + }, + + dispatchCancelTestImportList() { + dispatch(cancelTestImportList({ section })); + }, + + dispatchCancelSaveImportList() { + dispatch(cancelSaveImportList({ section })); + } + }; +} + +class EditImportListModalConnector extends Component { + + // + // Listeners + + onModalClose = () => { + this.props.dispatchClearPendingChanges(); + this.props.dispatchCancelTestImportList(); + this.props.dispatchCancelSaveImportList(); + this.props.onModalClose(); + } + + // + // Render + + render() { + const { + dispatchClearPendingChanges, + dispatchCancelTestImportList, + dispatchCancelSaveImportList, + ...otherProps + } = this.props; + + return ( + + ); + } +} + +EditImportListModalConnector.propTypes = { + onModalClose: PropTypes.func.isRequired, + dispatchClearPendingChanges: PropTypes.func.isRequired, + dispatchCancelTestImportList: PropTypes.func.isRequired, + dispatchCancelSaveImportList: PropTypes.func.isRequired +}; + +export default connect(null, createMapDispatchToProps)(EditImportListModalConnector); diff --git a/frontend/src/Settings/NetImport/NetImport/EditNetImportModalContent.css b/frontend/src/Settings/ImportLists/ImportLists/EditImportListModalContent.css similarity index 100% rename from frontend/src/Settings/NetImport/NetImport/EditNetImportModalContent.css rename to frontend/src/Settings/ImportLists/ImportLists/EditImportListModalContent.css diff --git a/frontend/src/Settings/NetImport/NetImport/EditNetImportModalContent.js b/frontend/src/Settings/ImportLists/ImportLists/EditImportListModalContent.js similarity index 88% rename from frontend/src/Settings/NetImport/NetImport/EditNetImportModalContent.js rename to frontend/src/Settings/ImportLists/ImportLists/EditImportListModalContent.js index b9fbe1752..6dc0b6f27 100644 --- a/frontend/src/Settings/NetImport/NetImport/EditNetImportModalContent.js +++ b/frontend/src/Settings/ImportLists/ImportLists/EditImportListModalContent.js @@ -14,9 +14,9 @@ import ModalFooter from 'Components/Modal/ModalFooter'; import ModalHeader from 'Components/Modal/ModalHeader'; import { inputTypes, kinds } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; -import styles from './EditNetImportModalContent.css'; +import styles from './EditImportListModalContent.css'; -function EditNetImportModalContent(props) { +function EditImportListModalContent(props) { const { advancedSettings, isFetching, @@ -30,7 +30,7 @@ function EditNetImportModalContent(props) { onModalClose, onSavePress, onTestPress, - onDeleteNetImportPress, + onDeleteImportListPress, ...otherProps } = props; @@ -44,6 +44,7 @@ function EditNetImportModalContent(props) { minimumAvailability, qualityProfileId, rootFolderPath, + searchOnAdd, tags, fields } = item; @@ -117,6 +118,21 @@ function EditNetImportModalContent(props) { /> + { + shouldMonitor && + + Search on Add + + + + } + {translate('MinimumAvailability')} {translate('Delete')} @@ -217,7 +233,7 @@ function EditNetImportModalContent(props) { ); } -EditNetImportModalContent.propTypes = { +EditImportListModalContent.propTypes = { advancedSettings: PropTypes.bool.isRequired, isFetching: PropTypes.bool.isRequired, error: PropTypes.object, @@ -230,7 +246,7 @@ EditNetImportModalContent.propTypes = { onModalClose: PropTypes.func.isRequired, onSavePress: PropTypes.func.isRequired, onTestPress: PropTypes.func.isRequired, - onDeleteNetImportPress: PropTypes.func + onDeleteImportListPress: PropTypes.func }; -export default EditNetImportModalContent; +export default EditImportListModalContent; diff --git a/frontend/src/Settings/NetImport/NetImport/EditNetImportModalContentConnector.js b/frontend/src/Settings/ImportLists/ImportLists/EditImportListModalContentConnector.js similarity index 57% rename from frontend/src/Settings/NetImport/NetImport/EditNetImportModalContentConnector.js rename to frontend/src/Settings/ImportLists/ImportLists/EditImportListModalContentConnector.js index aaadf989c..3529a328f 100644 --- a/frontend/src/Settings/NetImport/NetImport/EditNetImportModalContentConnector.js +++ b/frontend/src/Settings/ImportLists/ImportLists/EditImportListModalContentConnector.js @@ -2,31 +2,31 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { saveNetImport, setNetImportFieldValue, setNetImportValue, testNetImport } from 'Store/Actions/settingsActions'; +import { saveImportList, setImportListFieldValue, setImportListValue, testImportList } from 'Store/Actions/settingsActions'; import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector'; -import EditNetImportModalContent from './EditNetImportModalContent'; +import EditImportListModalContent from './EditImportListModalContent'; function createMapStateToProps() { return createSelector( (state) => state.settings.advancedSettings, - createProviderSettingsSelector('netImports'), - (advancedSettings, netImport) => { + createProviderSettingsSelector('importLists'), + (advancedSettings, importList) => { return { advancedSettings, - ...netImport + ...importList }; } ); } const mapDispatchToProps = { - setNetImportValue, - setNetImportFieldValue, - saveNetImport, - testNetImport + setImportListValue, + setImportListFieldValue, + saveImportList, + testImportList }; -class EditNetImportModalContentConnector extends Component { +class EditImportListModalContentConnector extends Component { // // Lifecycle @@ -41,19 +41,19 @@ class EditNetImportModalContentConnector extends Component { // Listeners onInputChange = ({ name, value }) => { - this.props.setNetImportValue({ name, value }); + this.props.setImportListValue({ name, value }); } onFieldChange = ({ name, value }) => { - this.props.setNetImportFieldValue({ name, value }); + this.props.setImportListFieldValue({ name, value }); } onSavePress = () => { - this.props.saveNetImport({ id: this.props.id }); + this.props.saveImportList({ id: this.props.id }); } onTestPress = () => { - this.props.testNetImport({ id: this.props.id }); + this.props.testImportList({ id: this.props.id }); } // @@ -61,7 +61,7 @@ class EditNetImportModalContentConnector extends Component { render() { return ( - { - this.setState({ isEditNetImportModalOpen: true }); + onEditImportListPress = () => { + this.setState({ isEditImportListModalOpen: true }); } - onEditNetImportModalClose = () => { - this.setState({ isEditNetImportModalOpen: false }); + onEditImportListModalClose = () => { + this.setState({ isEditImportListModalOpen: false }); } - onDeleteNetImportPress = () => { + onDeleteImportListPress = () => { this.setState({ - isEditNetImportModalOpen: false, - isDeleteNetImportModalOpen: true + isEditImportListModalOpen: false, + isDeleteImportListModalOpen: true }); } - onDeleteNetImportModalClose= () => { - this.setState({ isDeleteNetImportModalOpen: false }); + onDeleteImportListModalClose= () => { + this.setState({ isDeleteImportListModalOpen: false }); } - onConfirmDeleteNetImport = () => { - this.props.onConfirmDeleteNetImport(this.props.id); + onConfirmDeleteImportList = () => { + this.props.onConfirmDeleteImportList(this.props.id); } // @@ -61,9 +61,9 @@ class NetImport extends Component { return (
{name} @@ -96,33 +96,33 @@ class NetImport extends Component { }
-
); } } -NetImport.propTypes = { +ImportList.propTypes = { id: PropTypes.number.isRequired, name: PropTypes.string.isRequired, enabled: PropTypes.bool.isRequired, enableAuto: PropTypes.bool.isRequired, - onConfirmDeleteNetImport: PropTypes.func.isRequired + onConfirmDeleteImportList: PropTypes.func.isRequired }; -export default NetImport; +export default ImportList; diff --git a/frontend/src/Settings/NetImport/NetImport/NetImports.css b/frontend/src/Settings/ImportLists/ImportLists/ImportLists.css similarity index 77% rename from frontend/src/Settings/NetImport/NetImport/NetImports.css rename to frontend/src/Settings/ImportLists/ImportLists/ImportLists.css index 5011ad818..1b412d280 100644 --- a/frontend/src/Settings/NetImport/NetImport/NetImports.css +++ b/frontend/src/Settings/ImportLists/ImportLists/ImportLists.css @@ -1,10 +1,10 @@ -.netImports { +.importLists { display: flex; flex-wrap: wrap; } -.addNetImport { - composes: netImport from '~./NetImport.css'; +.addImportList { + composes: importList from '~./ImportList.css'; background-color: $cardAlternateBackgroundColor; color: $gray; diff --git a/frontend/src/Settings/NetImport/NetImport/NetImports.js b/frontend/src/Settings/ImportLists/ImportLists/ImportLists.js similarity index 51% rename from frontend/src/Settings/NetImport/NetImport/NetImports.js rename to frontend/src/Settings/ImportLists/ImportLists/ImportLists.js index d847a5b8e..aa5791017 100644 --- a/frontend/src/Settings/NetImport/NetImport/NetImports.js +++ b/frontend/src/Settings/ImportLists/ImportLists/ImportLists.js @@ -6,12 +6,12 @@ import Icon from 'Components/Icon'; import PageSectionContent from 'Components/Page/PageSectionContent'; import { icons } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; -import AddNetImportModal from './AddNetImportModal'; -import EditNetImportModalConnector from './EditNetImportModalConnector'; -import NetImport from './NetImport'; -import styles from './NetImports.css'; +import AddImportListModal from './AddImportListModal'; +import EditImportListModalConnector from './EditImportListModalConnector'; +import ImportList from './ImportList'; +import styles from './ImportLists.css'; -class NetImports extends Component { +class ImportLists extends Component { // // Lifecycle @@ -20,27 +20,27 @@ class NetImports extends Component { super(props, context); this.state = { - isAddNetImportModalOpen: false, - isEditNetImportModalOpen: false + isAddImportListModalOpen: false, + isEditImportListModalOpen: false }; } // // Listeners - onAddNetImportPress = () => { - this.setState({ isAddNetImportModalOpen: true }); + onAddImportListPress = () => { + this.setState({ isAddImportListModalOpen: true }); } - onAddNetImportModalClose = ({ netImportSelected = false } = {}) => { + onAddImportListModalClose = ({ importListSelected = false } = {}) => { this.setState({ - isAddNetImportModalOpen: false, - isEditNetImportModalOpen: netImportSelected + isAddImportListModalOpen: false, + isEditImportListModalOpen: importListSelected }); } - onEditNetImportModalClose = () => { - this.setState({ isEditNetImportModalOpen: false }); + onEditImportListModalClose = () => { + this.setState({ isEditImportListModalOpen: false }); } // @@ -49,13 +49,13 @@ class NetImports extends Component { render() { const { items, - onConfirmDeleteNetImport, + onConfirmDeleteImportList, ...otherProps } = this.props; const { - isAddNetImportModalOpen, - isEditNetImportModalOpen + isAddImportListModalOpen, + isEditImportListModalOpen } = this.state; return ( @@ -64,22 +64,22 @@ class NetImports extends Component { errorMessage={translate('UnableToLoadLists')} {...otherProps} > -
+
{ items.map((item) => { return ( - ); }) }
- -
@@ -105,11 +105,11 @@ class NetImports extends Component { } } -NetImports.propTypes = { +ImportLists.propTypes = { isFetching: PropTypes.bool.isRequired, error: PropTypes.object, items: PropTypes.arrayOf(PropTypes.object).isRequired, - onConfirmDeleteNetImport: PropTypes.func.isRequired + onConfirmDeleteImportList: PropTypes.func.isRequired }; -export default NetImports; +export default ImportLists; diff --git a/frontend/src/Settings/NetImport/NetImport/NetImportsConnector.js b/frontend/src/Settings/ImportLists/ImportLists/ImportListsConnector.js similarity index 54% rename from frontend/src/Settings/NetImport/NetImport/NetImportsConnector.js rename to frontend/src/Settings/ImportLists/ImportLists/ImportListsConnector.js index 24fd3f62d..67cfcdd22 100644 --- a/frontend/src/Settings/NetImport/NetImport/NetImportsConnector.js +++ b/frontend/src/Settings/ImportLists/ImportLists/ImportListsConnector.js @@ -3,39 +3,39 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import { fetchRootFolders } from 'Store/Actions/rootFolderActions'; -import { deleteNetImport, fetchNetImports } from 'Store/Actions/settingsActions'; +import { deleteImportList, fetchImportLists } from 'Store/Actions/settingsActions'; import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector'; import sortByName from 'Utilities/Array/sortByName'; -import NetImports from './NetImports'; +import ImportLists from './ImportLists'; function createMapStateToProps() { return createSelector( - createSortedSectionSelector('settings.netImports', sortByName), - (netImports) => netImports + createSortedSectionSelector('settings.importLists', sortByName), + (importLists) => importLists ); } const mapDispatchToProps = { - fetchNetImports, - deleteNetImport, + fetchImportLists, + deleteImportList, fetchRootFolders }; -class NetImportsConnector extends Component { +class ImportListsConnector extends Component { // // Lifecycle componentDidMount() { - this.props.fetchNetImports(); + this.props.fetchImportLists(); this.props.fetchRootFolders(); } // // Listeners - onConfirmDeleteNetImport = (id) => { - this.props.deleteNetImport({ id }); + onConfirmDeleteImportList = (id) => { + this.props.deleteImportList({ id }); } // @@ -43,18 +43,18 @@ class NetImportsConnector extends Component { render() { return ( - ); } } -NetImportsConnector.propTypes = { - fetchNetImports: PropTypes.func.isRequired, - deleteNetImport: PropTypes.func.isRequired, +ImportListsConnector.propTypes = { + fetchImportLists: PropTypes.func.isRequired, + deleteImportList: PropTypes.func.isRequired, fetchRootFolders: PropTypes.func.isRequired }; -export default connect(createMapStateToProps, mapDispatchToProps)(NetImportsConnector); +export default connect(createMapStateToProps, mapDispatchToProps)(ImportListsConnector); diff --git a/frontend/src/Settings/NetImport/Options/NetImportOptions.js b/frontend/src/Settings/ImportLists/Options/ImportListOptions.js similarity index 89% rename from frontend/src/Settings/NetImport/Options/NetImportOptions.js rename to frontend/src/Settings/ImportLists/Options/ImportListOptions.js index 9490b0b88..e31858813 100644 --- a/frontend/src/Settings/NetImport/Options/NetImportOptions.js +++ b/frontend/src/Settings/ImportLists/Options/ImportListOptions.js @@ -9,7 +9,7 @@ import LoadingIndicator from 'Components/Loading/LoadingIndicator'; import { inputTypes } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; -function NetImportOptions(props) { +function ImportListOptions(props) { const { isFetching, error, @@ -46,12 +46,12 @@ function NetImportOptions(props) { @@ -73,7 +73,7 @@ function NetImportOptions(props) { ); } -NetImportOptions.propTypes = { +ImportListOptions.propTypes = { advancedSettings: PropTypes.bool.isRequired, isFetching: PropTypes.bool.isRequired, error: PropTypes.object, @@ -82,4 +82,4 @@ NetImportOptions.propTypes = { onInputChange: PropTypes.func.isRequired }; -export default NetImportOptions; +export default ImportListOptions; diff --git a/frontend/src/Settings/NetImport/Options/NetImportOptionsConnector.js b/frontend/src/Settings/ImportLists/Options/ImportListOptionsConnector.js similarity index 64% rename from frontend/src/Settings/NetImport/Options/NetImportOptionsConnector.js rename to frontend/src/Settings/ImportLists/Options/ImportListOptionsConnector.js index b7d934286..fa4aaaa96 100644 --- a/frontend/src/Settings/NetImport/Options/NetImportOptionsConnector.js +++ b/frontend/src/Settings/ImportLists/Options/ImportListOptionsConnector.js @@ -3,11 +3,11 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import { clearPendingChanges } from 'Store/Actions/baseActions'; -import { fetchNetImportOptions, saveNetImportOptions, setNetImportOptionsValue } from 'Store/Actions/settingsActions'; +import { fetchImportListOptions, saveImportListOptions, setImportListOptionsValue } from 'Store/Actions/settingsActions'; import createSettingsSectionSelector from 'Store/Selectors/createSettingsSectionSelector'; -import NetImportOptions from './NetImportOptions'; +import ImportListOptions from './ImportListOptions'; -const SECTION = 'netImportOptions'; +const SECTION = 'importListOptions'; function createMapStateToProps() { return createSelector( @@ -23,26 +23,26 @@ function createMapStateToProps() { } const mapDispatchToProps = { - dispatchFetchNetImportOptions: fetchNetImportOptions, - dispatchSetNetImportOptionsValue: setNetImportOptionsValue, - dispatchSaveNetImportOptions: saveNetImportOptions, + dispatchFetchImportListOptions: fetchImportListOptions, + dispatchSetImportListOptionsValue: setImportListOptionsValue, + dispatchSaveImportListOptions: saveImportListOptions, dispatchClearPendingChanges: clearPendingChanges }; -class NetImportOptionsConnector extends Component { +class ImportListOptionsConnector extends Component { // // Lifecycle componentDidMount() { const { - dispatchFetchNetImportOptions, - dispatchSaveNetImportOptions, + dispatchFetchImportListOptions, + dispatchSaveImportListOptions, onChildMounted } = this.props; - dispatchFetchNetImportOptions(); - onChildMounted(dispatchSaveNetImportOptions); + dispatchFetchImportListOptions(); + onChildMounted(dispatchSaveImportListOptions); } componentDidUpdate(prevProps) { @@ -71,7 +71,7 @@ class NetImportOptionsConnector extends Component { // Listeners onInputChange = ({ name, value }) => { - this.props.dispatchSetNetImportOptionsValue({ name, value }); + this.props.dispatchSetImportListOptionsValue({ name, value }); } // @@ -79,7 +79,7 @@ class NetImportOptionsConnector extends Component { render() { return ( - @@ -87,15 +87,15 @@ class NetImportOptionsConnector extends Component { } } -NetImportOptionsConnector.propTypes = { +ImportListOptionsConnector.propTypes = { isSaving: PropTypes.bool.isRequired, hasPendingChanges: PropTypes.bool.isRequired, - dispatchFetchNetImportOptions: PropTypes.func.isRequired, - dispatchSetNetImportOptionsValue: PropTypes.func.isRequired, - dispatchSaveNetImportOptions: PropTypes.func.isRequired, + dispatchFetchImportListOptions: PropTypes.func.isRequired, + dispatchSetImportListOptionsValue: PropTypes.func.isRequired, + dispatchSaveImportListOptions: PropTypes.func.isRequired, dispatchClearPendingChanges: PropTypes.func.isRequired, onChildMounted: PropTypes.func.isRequired, onChildStateChange: PropTypes.func.isRequired }; -export default connect(createMapStateToProps, mapDispatchToProps)(NetImportOptionsConnector); +export default connect(createMapStateToProps, mapDispatchToProps)(ImportListOptionsConnector); diff --git a/frontend/src/Settings/NetImport/NetImport/EditNetImportModalConnector.js b/frontend/src/Settings/NetImport/NetImport/EditNetImportModalConnector.js deleted file mode 100644 index c96311c2e..000000000 --- a/frontend/src/Settings/NetImport/NetImport/EditNetImportModalConnector.js +++ /dev/null @@ -1,65 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { clearPendingChanges } from 'Store/Actions/baseActions'; -import { cancelSaveNetImport, cancelTestNetImport } from 'Store/Actions/settingsActions'; -import EditNetImportModal from './EditNetImportModal'; - -function createMapDispatchToProps(dispatch, props) { - const section = 'settings.netImports'; - - return { - dispatchClearPendingChanges() { - dispatch(clearPendingChanges({ section })); - }, - - dispatchCancelTestNetImport() { - dispatch(cancelTestNetImport({ section })); - }, - - dispatchCancelSaveNetImport() { - dispatch(cancelSaveNetImport({ section })); - } - }; -} - -class EditNetImportModalConnector extends Component { - - // - // Listeners - - onModalClose = () => { - this.props.dispatchClearPendingChanges(); - this.props.dispatchCancelTestNetImport(); - this.props.dispatchCancelSaveNetImport(); - this.props.onModalClose(); - } - - // - // Render - - render() { - const { - dispatchClearPendingChanges, - dispatchCancelTestNetImport, - dispatchCancelSaveNetImport, - ...otherProps - } = this.props; - - return ( - - ); - } -} - -EditNetImportModalConnector.propTypes = { - onModalClose: PropTypes.func.isRequired, - dispatchClearPendingChanges: PropTypes.func.isRequired, - dispatchCancelTestNetImport: PropTypes.func.isRequired, - dispatchCancelSaveNetImport: PropTypes.func.isRequired -}; - -export default connect(null, createMapDispatchToProps)(EditNetImportModalConnector); diff --git a/frontend/src/Settings/NetImport/NetImportExclusions/NetImportExclusionsConnector.js b/frontend/src/Settings/NetImport/NetImportExclusions/NetImportExclusionsConnector.js deleted file mode 100644 index 199282665..000000000 --- a/frontend/src/Settings/NetImport/NetImportExclusions/NetImportExclusionsConnector.js +++ /dev/null @@ -1,59 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; -import { deleteNetImportExclusion, fetchNetImportExclusions } from 'Store/Actions/settingsActions'; -import NetImportExclusions from './NetImportExclusions'; - -function createMapStateToProps() { - return createSelector( - (state) => state.settings.netImportExclusions, - (netImportExclusions) => { - return { - ...netImportExclusions - }; - } - ); -} - -const mapDispatchToProps = { - fetchNetImportExclusions, - deleteNetImportExclusion -}; - -class NetImportExclusionsConnector extends Component { - - // - // Lifecycle - - componentDidMount() { - this.props.fetchNetImportExclusions(); - } - - // - // Listeners - - onConfirmDeleteNetImportExclusion = (id) => { - this.props.deleteNetImportExclusion({ id }); - } - - // - // Render - - render() { - return ( - - ); - } -} - -NetImportExclusionsConnector.propTypes = { - fetchNetImportExclusions: PropTypes.func.isRequired, - deleteNetImportExclusion: PropTypes.func.isRequired -}; - -export default connect(createMapStateToProps, mapDispatchToProps)(NetImportExclusionsConnector); diff --git a/frontend/src/Settings/Settings.js b/frontend/src/Settings/Settings.js index 4370346d3..91dccbef9 100644 --- a/frontend/src/Settings/Settings.js +++ b/frontend/src/Settings/Settings.js @@ -82,7 +82,7 @@ function Settings() { {translate('Lists')} diff --git a/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js b/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js index 341a63f46..b8977e966 100644 --- a/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js +++ b/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js @@ -21,7 +21,7 @@ function TagDetailsModalContent(props) { delayProfiles, notifications, restrictions, - netImports, + importLists, onModalClose, onDeleteTagPress } = props; @@ -144,10 +144,10 @@ function TagDetailsModalContent(props) { } { - !!netImports.length && + !!importLists.length &&
{ - netImports.map((item) => { + importLists.map((item) => { return (
{item.name} @@ -189,7 +189,7 @@ TagDetailsModalContent.propTypes = { delayProfiles: PropTypes.arrayOf(PropTypes.object).isRequired, notifications: PropTypes.arrayOf(PropTypes.object).isRequired, restrictions: PropTypes.arrayOf(PropTypes.object).isRequired, - netImports: PropTypes.arrayOf(PropTypes.object).isRequired, + importLists: PropTypes.arrayOf(PropTypes.object).isRequired, onModalClose: PropTypes.func.isRequired, onDeleteTagPress: PropTypes.func.isRequired }; diff --git a/frontend/src/Settings/Tags/Details/TagDetailsModalContentConnector.js b/frontend/src/Settings/Tags/Details/TagDetailsModalContentConnector.js index 864d81a94..defb88635 100644 --- a/frontend/src/Settings/Tags/Details/TagDetailsModalContentConnector.js +++ b/frontend/src/Settings/Tags/Details/TagDetailsModalContentConnector.js @@ -61,10 +61,10 @@ function createMatchingRestrictionsSelector() { ); } -function createMatchingNetImportsSelector() { +function createMatchingImportListsSelector() { return createSelector( - (state, { netImportIds }) => netImportIds, - (state) => state.settings.netImports.items, + (state, { importListIds }) => importListIds, + (state) => state.settings.importLists.items, findMatchingItems ); } @@ -75,14 +75,14 @@ function createMapStateToProps() { createMatchingDelayProfilesSelector(), createMatchingNotificationsSelector(), createMatchingRestrictionsSelector(), - createMatchingNetImportsSelector(), - (movies, delayProfiles, notifications, restrictions, netImports) => { + createMatchingImportListsSelector(), + (movies, delayProfiles, notifications, restrictions, importLists) => { return { movies, delayProfiles, notifications, restrictions, - netImports + importLists }; } ); diff --git a/frontend/src/Settings/Tags/Tag.js b/frontend/src/Settings/Tags/Tag.js index a8680db12..9e3693d2c 100644 --- a/frontend/src/Settings/Tags/Tag.js +++ b/frontend/src/Settings/Tags/Tag.js @@ -56,7 +56,7 @@ class Tag extends Component { delayProfileIds, notificationIds, restrictionIds, - netImportIds, + importListIds, movieIds } = this.props; @@ -69,7 +69,7 @@ class Tag extends Component { delayProfileIds.length || notificationIds.length || restrictionIds.length || - netImportIds.length || + importListIds.length || movieIds.length ); @@ -115,9 +115,9 @@ class Tag extends Component { } { - !!netImportIds.length && + !!importListIds.length &&
- {netImportIds.length} list{netImportIds.length > 1 && 's'} + {importListIds.length} list{importListIds.length > 1 && 's'}
}
@@ -137,7 +137,7 @@ class Tag extends Component { delayProfileIds={delayProfileIds} notificationIds={notificationIds} restrictionIds={restrictionIds} - netImportIds={netImportIds} + importListIds={importListIds} isOpen={isDetailsModalOpen} onModalClose={this.onDetailsModalClose} onDeleteTagPress={this.onDeleteTagPress} @@ -163,7 +163,7 @@ Tag.propTypes = { delayProfileIds: PropTypes.arrayOf(PropTypes.number).isRequired, notificationIds: PropTypes.arrayOf(PropTypes.number).isRequired, restrictionIds: PropTypes.arrayOf(PropTypes.number).isRequired, - netImportIds: PropTypes.arrayOf(PropTypes.number).isRequired, + importListIds: PropTypes.arrayOf(PropTypes.number).isRequired, movieIds: PropTypes.arrayOf(PropTypes.number).isRequired, onConfirmDeleteTag: PropTypes.func.isRequired }; @@ -172,7 +172,7 @@ Tag.defaultProps = { delayProfileIds: [], notificationIds: [], restrictionIds: [], - netImportIds: [], + importListIds: [], movieIds: [] }; diff --git a/frontend/src/Settings/Tags/TagsConnector.js b/frontend/src/Settings/Tags/TagsConnector.js index a981eed2a..88ffcd776 100644 --- a/frontend/src/Settings/Tags/TagsConnector.js +++ b/frontend/src/Settings/Tags/TagsConnector.js @@ -2,7 +2,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { fetchDelayProfiles, fetchNetImports, fetchNotifications, fetchRestrictions } from 'Store/Actions/settingsActions'; +import { fetchDelayProfiles, fetchImportLists, fetchNotifications, fetchRestrictions } from 'Store/Actions/settingsActions'; import { fetchTagDetails } from 'Store/Actions/tagActions'; import Tags from './Tags'; @@ -29,7 +29,7 @@ const mapDispatchToProps = { dispatchFetchDelayProfiles: fetchDelayProfiles, dispatchFetchNotifications: fetchNotifications, dispatchFetchRestrictions: fetchRestrictions, - dispatchFetchNetImports: fetchNetImports + dispatchFetchImportLists: fetchImportLists }; class MetadatasConnector extends Component { @@ -43,14 +43,14 @@ class MetadatasConnector extends Component { dispatchFetchDelayProfiles, dispatchFetchNotifications, dispatchFetchRestrictions, - dispatchFetchNetImports + dispatchFetchImportLists } = this.props; dispatchFetchTagDetails(); dispatchFetchDelayProfiles(); dispatchFetchNotifications(); dispatchFetchRestrictions(); - dispatchFetchNetImports(); + dispatchFetchImportLists(); } // @@ -70,7 +70,7 @@ MetadatasConnector.propTypes = { dispatchFetchDelayProfiles: PropTypes.func.isRequired, dispatchFetchNotifications: PropTypes.func.isRequired, dispatchFetchRestrictions: PropTypes.func.isRequired, - dispatchFetchNetImports: PropTypes.func.isRequired + dispatchFetchImportLists: PropTypes.func.isRequired }; export default connect(createMapStateToProps, mapDispatchToProps)(MetadatasConnector); diff --git a/frontend/src/Store/Actions/Settings/importExclusions.js b/frontend/src/Store/Actions/Settings/importExclusions.js new file mode 100644 index 000000000..17812fa8f --- /dev/null +++ b/frontend/src/Store/Actions/Settings/importExclusions.js @@ -0,0 +1,71 @@ +import { createAction } from 'redux-actions'; +import createFetchHandler from 'Store/Actions/Creators/createFetchHandler'; +import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler'; +import createSaveProviderHandler from 'Store/Actions/Creators/createSaveProviderHandler'; +import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer'; +import { createThunk } from 'Store/thunks'; + +// +// Variables + +const section = 'settings.importExclusions'; + +// +// Actions Types + +export const FETCH_IMPORT_EXCLUSIONS = 'settings/importExclusions/fetchImportExclusions'; +export const SAVE_IMPORT_EXCLUSION = 'settings/importExclusions/saveImportExclusion'; +export const DELETE_IMPORT_EXCLUSION = 'settings/importExclusions/deleteImportExclusion'; +export const SET_IMPORT_EXCLUSION_VALUE = 'settings/importExclusions/setImportExclusionValue'; + +// +// Action Creators + +export const fetchImportExclusions = createThunk(FETCH_IMPORT_EXCLUSIONS); + +export const saveImportExclusion = createThunk(SAVE_IMPORT_EXCLUSION); +export const deleteImportExclusion = createThunk(DELETE_IMPORT_EXCLUSION); + +export const setImportExclusionValue = createAction(SET_IMPORT_EXCLUSION_VALUE, (payload) => { + return { + section, + ...payload + }; +}); + +// +// Details + +export default { + + // + // State + + defaultState: { + isFetching: false, + isPopulated: false, + error: null, + items: [], + isSaving: false, + saveError: null, + pendingChanges: {} + }, + + // + // Action Handlers + + actionHandlers: { + [FETCH_IMPORT_EXCLUSIONS]: createFetchHandler(section, '/exclusions'), + + [SAVE_IMPORT_EXCLUSION]: createSaveProviderHandler(section, '/exclusions'), + [DELETE_IMPORT_EXCLUSION]: createRemoveItemHandler(section, '/exclusions') + }, + + // + // Reducers + + reducers: { + [SET_IMPORT_EXCLUSION_VALUE]: createSetSettingValueReducer(section) + } + +}; diff --git a/frontend/src/Store/Actions/Settings/importListOptions.js b/frontend/src/Store/Actions/Settings/importListOptions.js new file mode 100644 index 000000000..e33c80770 --- /dev/null +++ b/frontend/src/Store/Actions/Settings/importListOptions.js @@ -0,0 +1,64 @@ +import { createAction } from 'redux-actions'; +import createFetchHandler from 'Store/Actions/Creators/createFetchHandler'; +import createSaveHandler from 'Store/Actions/Creators/createSaveHandler'; +import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer'; +import { createThunk } from 'Store/thunks'; + +// +// Variables + +const section = 'settings.importListOptions'; + +// +// Actions Types + +export const FETCH_IMPORT_LIST_OPTIONS = 'settings/importListOptions/fetchImportListOptions'; +export const SAVE_IMPORT_LIST_OPTIONS = 'settings/importListOptions/saveImportListOptions'; +export const SET_IMPORT_LIST_OPTIONS_VALUE = 'settings/importListOptions/setImportListOptionsValue'; + +// +// Action Creators + +export const fetchImportListOptions = createThunk(FETCH_IMPORT_LIST_OPTIONS); +export const saveImportListOptions = createThunk(SAVE_IMPORT_LIST_OPTIONS); +export const setImportListOptionsValue = createAction(SET_IMPORT_LIST_OPTIONS_VALUE, (payload) => { + return { + section, + ...payload + }; +}); + +// +// Details + +export default { + + // + // State + + defaultState: { + isFetching: false, + isPopulated: false, + error: null, + pendingChanges: {}, + isSaving: false, + saveError: null, + item: {} + }, + + // + // Action Handlers + + actionHandlers: { + [FETCH_IMPORT_LIST_OPTIONS]: createFetchHandler(section, '/config/importlist'), + [SAVE_IMPORT_LIST_OPTIONS]: createSaveHandler(section, '/config/importlist') + }, + + // + // Reducers + + reducers: { + [SET_IMPORT_LIST_OPTIONS_VALUE]: createSetSettingValueReducer(section) + } + +}; diff --git a/frontend/src/Store/Actions/Settings/importLists.js b/frontend/src/Store/Actions/Settings/importLists.js new file mode 100644 index 000000000..9f7854224 --- /dev/null +++ b/frontend/src/Store/Actions/Settings/importLists.js @@ -0,0 +1,116 @@ +import { createAction } from 'redux-actions'; +import createFetchHandler from 'Store/Actions/Creators/createFetchHandler'; +import createFetchSchemaHandler from 'Store/Actions/Creators/createFetchSchemaHandler'; +import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler'; +import createSaveProviderHandler, { createCancelSaveProviderHandler } from 'Store/Actions/Creators/createSaveProviderHandler'; +import createTestAllProvidersHandler from 'Store/Actions/Creators/createTestAllProvidersHandler'; +import createTestProviderHandler, { createCancelTestProviderHandler } from 'Store/Actions/Creators/createTestProviderHandler'; +import createSetProviderFieldValueReducer from 'Store/Actions/Creators/Reducers/createSetProviderFieldValueReducer'; +import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer'; +import { createThunk } from 'Store/thunks'; +import selectProviderSchema from 'Utilities/State/selectProviderSchema'; + +// +// Variables + +const section = 'settings.importLists'; + +// +// Actions Types + +export const FETCH_IMPORT_LISTS = 'settings/importLists/fetchImportLists'; +export const FETCH_IMPORT_LIST_SCHEMA = 'settings/importLists/fetchImportListSchema'; +export const SELECT_IMPORT_LIST_SCHEMA = 'settings/importLists/selectImportListSchema'; +export const SET_IMPORT_LIST_VALUE = 'settings/importLists/setImportListValue'; +export const SET_IMPORT_LIST_FIELD_VALUE = 'settings/importLists/setImportListFieldValue'; +export const SAVE_IMPORT_LIST = 'settings/importLists/saveImportList'; +export const CANCEL_SAVE_IMPORT_LIST = 'settings/importLists/cancelSaveImportList'; +export const DELETE_IMPORT_LIST = 'settings/importLists/deleteImportList'; +export const TEST_IMPORT_LIST = 'settings/importLists/testImportList'; +export const CANCEL_TEST_IMPORT_LIST = 'settings/importLists/cancelTestImportList'; +export const TEST_ALL_IMPORT_LIST = 'settings/importLists/testAllImportList'; + +// +// Action Creators + +export const fetchImportLists = createThunk(FETCH_IMPORT_LISTS); +export const fetchImportListSchema = createThunk(FETCH_IMPORT_LIST_SCHEMA); +export const selectImportListSchema = createAction(SELECT_IMPORT_LIST_SCHEMA); + +export const saveImportList = createThunk(SAVE_IMPORT_LIST); +export const cancelSaveImportList = createThunk(CANCEL_SAVE_IMPORT_LIST); +export const deleteImportList = createThunk(DELETE_IMPORT_LIST); +export const testImportList = createThunk(TEST_IMPORT_LIST); +export const cancelTestImportList = createThunk(CANCEL_TEST_IMPORT_LIST); +export const testAllImportList = createThunk(TEST_ALL_IMPORT_LIST); + +export const setImportListValue = createAction(SET_IMPORT_LIST_VALUE, (payload) => { + return { + section, + ...payload + }; +}); + +export const setImportListFieldValue = createAction(SET_IMPORT_LIST_FIELD_VALUE, (payload) => { + return { + section, + ...payload + }; +}); + +// +// Details + +export default { + + // + // State + + defaultState: { + isFetching: false, + isPopulated: false, + error: null, + isSchemaFetching: false, + isSchemaPopulated: false, + schemaError: null, + schema: [], + selectedSchema: {}, + isSaving: false, + saveError: null, + isTesting: false, + isTestingAll: false, + items: [], + pendingChanges: {} + }, + + // + // Action Handlers + + actionHandlers: { + [FETCH_IMPORT_LISTS]: createFetchHandler(section, '/importlist'), + [FETCH_IMPORT_LIST_SCHEMA]: createFetchSchemaHandler(section, '/importlist/schema'), + + [SAVE_IMPORT_LIST]: createSaveProviderHandler(section, '/importlist'), + [CANCEL_SAVE_IMPORT_LIST]: createCancelSaveProviderHandler(section), + [DELETE_IMPORT_LIST]: createRemoveItemHandler(section, '/importlist'), + [TEST_IMPORT_LIST]: createTestProviderHandler(section, '/importlist'), + [CANCEL_TEST_IMPORT_LIST]: createCancelTestProviderHandler(section), + [TEST_ALL_IMPORT_LIST]: createTestAllProvidersHandler(section, '/importlist') + }, + + // + // Reducers + + reducers: { + [SET_IMPORT_LIST_VALUE]: createSetSettingValueReducer(section), + [SET_IMPORT_LIST_FIELD_VALUE]: createSetProviderFieldValueReducer(section), + + [SELECT_IMPORT_LIST_SCHEMA]: (state, { payload }) => { + return selectProviderSchema(state, section, payload, (selectedSchema) => { + + return selectedSchema; + }); + } + } + +}; diff --git a/frontend/src/Store/Actions/Settings/netImportExclusions.js b/frontend/src/Store/Actions/Settings/netImportExclusions.js deleted file mode 100644 index 7823a23a8..000000000 --- a/frontend/src/Store/Actions/Settings/netImportExclusions.js +++ /dev/null @@ -1,71 +0,0 @@ -import { createAction } from 'redux-actions'; -import createFetchHandler from 'Store/Actions/Creators/createFetchHandler'; -import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler'; -import createSaveProviderHandler from 'Store/Actions/Creators/createSaveProviderHandler'; -import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer'; -import { createThunk } from 'Store/thunks'; - -// -// Variables - -const section = 'settings.netImportExclusions'; - -// -// Actions Types - -export const FETCH_NET_IMPORT_EXCLUSIONS = 'settings/netImportExclusions/fetchNetImportExclusions'; -export const SAVE_NET_IMPORT_EXCLUSION = 'settings/netImportExclusions/saveNetImportExclusion'; -export const DELETE_NET_IMPORT_EXCLUSION = 'settings/netImportExclusions/deleteNetImportExclusion'; -export const SET_NET_IMPORT_EXCLUSION_VALUE = 'settings/netImportExclusions/setNetImportExclusionValue'; - -// -// Action Creators - -export const fetchNetImportExclusions = createThunk(FETCH_NET_IMPORT_EXCLUSIONS); - -export const saveNetImportExclusion = createThunk(SAVE_NET_IMPORT_EXCLUSION); -export const deleteNetImportExclusion = createThunk(DELETE_NET_IMPORT_EXCLUSION); - -export const setNetImportExclusionValue = createAction(SET_NET_IMPORT_EXCLUSION_VALUE, (payload) => { - return { - section, - ...payload - }; -}); - -// -// Details - -export default { - - // - // State - - defaultState: { - isFetching: false, - isPopulated: false, - error: null, - items: [], - isSaving: false, - saveError: null, - pendingChanges: {} - }, - - // - // Action Handlers - - actionHandlers: { - [FETCH_NET_IMPORT_EXCLUSIONS]: createFetchHandler(section, '/exclusions'), - - [SAVE_NET_IMPORT_EXCLUSION]: createSaveProviderHandler(section, '/exclusions'), - [DELETE_NET_IMPORT_EXCLUSION]: createRemoveItemHandler(section, '/exclusions') - }, - - // - // Reducers - - reducers: { - [SET_NET_IMPORT_EXCLUSION_VALUE]: createSetSettingValueReducer(section) - } - -}; diff --git a/frontend/src/Store/Actions/Settings/netImportOptions.js b/frontend/src/Store/Actions/Settings/netImportOptions.js deleted file mode 100644 index 425f8f4e4..000000000 --- a/frontend/src/Store/Actions/Settings/netImportOptions.js +++ /dev/null @@ -1,64 +0,0 @@ -import { createAction } from 'redux-actions'; -import createFetchHandler from 'Store/Actions/Creators/createFetchHandler'; -import createSaveHandler from 'Store/Actions/Creators/createSaveHandler'; -import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer'; -import { createThunk } from 'Store/thunks'; - -// -// Variables - -const section = 'settings.netImportOptions'; - -// -// Actions Types - -export const FETCH_NET_IMPORT_OPTIONS = 'settings/netImportOptions/fetchNetImportOptions'; -export const SAVE_NET_IMPORT_OPTIONS = 'settings/netImportOptions/saveNetImportOptions'; -export const SET_NET_IMPORT_OPTIONS_VALUE = 'settings/netImportOptions/setNetImportOptionsValue'; - -// -// Action Creators - -export const fetchNetImportOptions = createThunk(FETCH_NET_IMPORT_OPTIONS); -export const saveNetImportOptions = createThunk(SAVE_NET_IMPORT_OPTIONS); -export const setNetImportOptionsValue = createAction(SET_NET_IMPORT_OPTIONS_VALUE, (payload) => { - return { - section, - ...payload - }; -}); - -// -// Details - -export default { - - // - // State - - defaultState: { - isFetching: false, - isPopulated: false, - error: null, - pendingChanges: {}, - isSaving: false, - saveError: null, - item: {} - }, - - // - // Action Handlers - - actionHandlers: { - [FETCH_NET_IMPORT_OPTIONS]: createFetchHandler(section, '/config/netimport'), - [SAVE_NET_IMPORT_OPTIONS]: createSaveHandler(section, '/config/netimport') - }, - - // - // Reducers - - reducers: { - [SET_NET_IMPORT_OPTIONS_VALUE]: createSetSettingValueReducer(section) - } - -}; diff --git a/frontend/src/Store/Actions/Settings/netImports.js b/frontend/src/Store/Actions/Settings/netImports.js deleted file mode 100644 index 300f1f7f9..000000000 --- a/frontend/src/Store/Actions/Settings/netImports.js +++ /dev/null @@ -1,116 +0,0 @@ -import { createAction } from 'redux-actions'; -import createFetchHandler from 'Store/Actions/Creators/createFetchHandler'; -import createFetchSchemaHandler from 'Store/Actions/Creators/createFetchSchemaHandler'; -import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler'; -import createSaveProviderHandler, { createCancelSaveProviderHandler } from 'Store/Actions/Creators/createSaveProviderHandler'; -import createTestAllProvidersHandler from 'Store/Actions/Creators/createTestAllProvidersHandler'; -import createTestProviderHandler, { createCancelTestProviderHandler } from 'Store/Actions/Creators/createTestProviderHandler'; -import createSetProviderFieldValueReducer from 'Store/Actions/Creators/Reducers/createSetProviderFieldValueReducer'; -import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer'; -import { createThunk } from 'Store/thunks'; -import selectProviderSchema from 'Utilities/State/selectProviderSchema'; - -// -// Variables - -const section = 'settings.netImports'; - -// -// Actions Types - -export const FETCH_NET_IMPORTS = 'settings/netImports/fetchNetImports'; -export const FETCH_NET_IMPORT_SCHEMA = 'settings/netImports/fetchNetImportSchema'; -export const SELECT_NET_IMPORT_SCHEMA = 'settings/netImports/selectNetImportSchema'; -export const SET_NET_IMPORT_VALUE = 'settings/netImports/setNetImportValue'; -export const SET_NET_IMPORT_FIELD_VALUE = 'settings/netImports/setNetImportFieldValue'; -export const SAVE_NET_IMPORT = 'settings/netImports/saveNetImport'; -export const CANCEL_SAVE_NET_IMPORT = 'settings/netImports/cancelSaveNetImport'; -export const DELETE_NET_IMPORT = 'settings/netImports/deleteNetImport'; -export const TEST_NET_IMPORT = 'settings/netImports/testNetImport'; -export const CANCEL_TEST_NET_IMPORT = 'settings/netImports/cancelTestNetImport'; -export const TEST_ALL_NET_IMPORT = 'settings/netImports/testAllNetImport'; - -// -// Action Creators - -export const fetchNetImports = createThunk(FETCH_NET_IMPORTS); -export const fetchNetImportSchema = createThunk(FETCH_NET_IMPORT_SCHEMA); -export const selectNetImportSchema = createAction(SELECT_NET_IMPORT_SCHEMA); - -export const saveNetImport = createThunk(SAVE_NET_IMPORT); -export const cancelSaveNetImport = createThunk(CANCEL_SAVE_NET_IMPORT); -export const deleteNetImport = createThunk(DELETE_NET_IMPORT); -export const testNetImport = createThunk(TEST_NET_IMPORT); -export const cancelTestNetImport = createThunk(CANCEL_TEST_NET_IMPORT); -export const testAllNetImport = createThunk(TEST_ALL_NET_IMPORT); - -export const setNetImportValue = createAction(SET_NET_IMPORT_VALUE, (payload) => { - return { - section, - ...payload - }; -}); - -export const setNetImportFieldValue = createAction(SET_NET_IMPORT_FIELD_VALUE, (payload) => { - return { - section, - ...payload - }; -}); - -// -// Details - -export default { - - // - // State - - defaultState: { - isFetching: false, - isPopulated: false, - error: null, - isSchemaFetching: false, - isSchemaPopulated: false, - schemaError: null, - schema: [], - selectedSchema: {}, - isSaving: false, - saveError: null, - isTesting: false, - isTestingAll: false, - items: [], - pendingChanges: {} - }, - - // - // Action Handlers - - actionHandlers: { - [FETCH_NET_IMPORTS]: createFetchHandler(section, '/netimport'), - [FETCH_NET_IMPORT_SCHEMA]: createFetchSchemaHandler(section, '/netimport/schema'), - - [SAVE_NET_IMPORT]: createSaveProviderHandler(section, '/netimport'), - [CANCEL_SAVE_NET_IMPORT]: createCancelSaveProviderHandler(section), - [DELETE_NET_IMPORT]: createRemoveItemHandler(section, '/netimport'), - [TEST_NET_IMPORT]: createTestProviderHandler(section, '/netimport'), - [CANCEL_TEST_NET_IMPORT]: createCancelTestProviderHandler(section), - [TEST_ALL_NET_IMPORT]: createTestAllProvidersHandler(section, '/netimport') - }, - - // - // Reducers - - reducers: { - [SET_NET_IMPORT_VALUE]: createSetSettingValueReducer(section), - [SET_NET_IMPORT_FIELD_VALUE]: createSetProviderFieldValueReducer(section), - - [SELECT_NET_IMPORT_SCHEMA]: (state, { payload }) => { - return selectProviderSchema(state, section, payload, (selectedSchema) => { - - return selectedSchema; - }); - } - } - -}; diff --git a/frontend/src/Store/Actions/discoverMovieActions.js b/frontend/src/Store/Actions/discoverMovieActions.js index 9cc9bd6d8..eae089019 100644 --- a/frontend/src/Store/Actions/discoverMovieActions.js +++ b/frontend/src/Store/Actions/discoverMovieActions.js @@ -40,6 +40,10 @@ export const defaultState = { secondarySortDirection: sortDirections.ASCENDING, view: 'overview', + options: { + includeRecommendations: true + }, + defaults: { rootFolderPath: '', monitor: 'true', @@ -57,7 +61,11 @@ export const defaultState = { overviewOptions: { detailedProgressBar: false, size: 'medium', - showStudio: true + showStudio: true, + showRatings: true, + showYear: true, + showCertification: true, + showGenres: true }, tableOptions: { @@ -72,6 +80,13 @@ export const defaultState = { isVisible: true, isModifiable: false }, + { + name: 'isRecommendation', + columnLabel: 'Recommedation', + isSortable: true, + isVisible: true, + isModifiable: false + }, { name: 'sortTitle', label: translate('MovieTitle'), @@ -79,6 +94,12 @@ export const defaultState = { isVisible: true, isModifiable: false }, + { + name: 'collection', + label: translate('Collection'), + isSortable: true, + isVisible: false + }, { name: 'studio', label: translate('Studio'), @@ -97,6 +118,18 @@ export const defaultState = { isSortable: true, isVisible: false }, + { + name: 'digitalRelease', + label: translate('DigitalRelease'), + isSortable: true, + isVisible: false + }, + { + name: 'runtime', + label: translate('Runtime'), + isSortable: true, + isVisible: false + }, { name: 'genres', label: translate('Genres'), @@ -115,6 +148,12 @@ export const defaultState = { isSortable: true, isVisible: false }, + { + name: 'lists', + label: 'Lists', + isSortable: false, + isVisible: false + }, { name: 'actions', columnLabel: translate('Actions'), @@ -146,6 +185,12 @@ export const defaultState = { return result; }, + collection: function(item) { + const { collection ={} } = item; + + return collection.name; + }, + studio: function(item) { const studio = item.studio; @@ -211,6 +256,25 @@ export const defaultState = { return tagList.sort(sortByName); } }, + { + name: 'collection', + label: translate('Collection'), + type: filterBuilderTypes.ARRAY, + optionsSelector: function(items) { + const collectionList = items.reduce((acc, movie) => { + if (movie.collection) { + acc.push({ + id: movie.collection.name, + name: movie.collection.name + }); + } + + return acc; + }, []); + + return collectionList.sort(sortByName); + } + }, { name: 'inCinemas', label: 'In Cinemas', @@ -223,6 +287,17 @@ export const defaultState = { type: filterBuilderTypes.DATE, valueType: filterBuilderValueTypes.DATE }, + { + name: 'digitalRelease', + label: 'Digital Release', + type: filterBuilderTypes.DATE, + valueType: filterBuilderValueTypes.DATE + }, + { + name: 'runtime', + label: translate('Runtime'), + type: filterBuilderTypes.NUMBER + }, { name: 'genres', label: 'Genres', @@ -252,6 +327,12 @@ export const defaultState = { label: 'Certification', type: filterBuilderTypes.EXACT }, + { + name: 'lists', + label: 'Lists', + type: filterBuilderTypes.ARRAY, + valueType: filterBuilderValueTypes.IMPORTLIST + }, { name: 'isExcluded', label: 'On Excluded List', @@ -263,6 +344,12 @@ export const defaultState = { label: 'Exists in Library', type: filterBuilderTypes.EXACT, valueType: filterBuilderValueTypes.BOOL + }, + { + name: 'isRecommendation', + label: 'Recommended', + type: filterBuilderTypes.EXACT, + valueType: filterBuilderValueTypes.BOOL } ] }; @@ -275,6 +362,7 @@ export const persistState = [ 'discoverMovie.customFilters', 'discoverMovie.view', 'discoverMovie.columns', + 'discoverMovie.options', 'discoverMovie.posterOptions', 'discoverMovie.overviewOptions', 'discoverMovie.tableOptions' @@ -294,11 +382,12 @@ export const FETCH_DISCOVER_MOVIES = 'discoverMovie/fetchDiscoverMovies'; export const SET_LIST_MOVIE_SORT = 'discoverMovie/setListMovieSort'; export const SET_LIST_MOVIE_FILTER = 'discoverMovie/setListMovieFilter'; export const SET_LIST_MOVIE_VIEW = 'discoverMovie/setListMovieView'; +export const SET_LIST_MOVIE_OPTION = 'discoverMovie/setListMovieMovieOption'; export const SET_LIST_MOVIE_TABLE_OPTION = 'discoverMovie/setListMovieTableOption'; export const SET_LIST_MOVIE_POSTER_OPTION = 'discoverMovie/setListMoviePosterOption'; export const SET_LIST_MOVIE_OVERVIEW_OPTION = 'discoverMovie/setListMovieOverviewOption'; -export const ADD_NET_IMPORT_EXCLUSIONS = 'discoverMovie/addNetImportExclusions'; +export const ADD_IMPORT_EXCLUSIONS = 'discoverMovie/addImportExclusions'; // // Action Creators @@ -313,11 +402,12 @@ export const fetchDiscoverMovies = createThunk(FETCH_DISCOVER_MOVIES); export const setListMovieSort = createAction(SET_LIST_MOVIE_SORT); export const setListMovieFilter = createAction(SET_LIST_MOVIE_FILTER); export const setListMovieView = createAction(SET_LIST_MOVIE_VIEW); +export const setListMovieOption = createAction(SET_LIST_MOVIE_OPTION); export const setListMovieTableOption = createAction(SET_LIST_MOVIE_TABLE_OPTION); export const setListMoviePosterOption = createAction(SET_LIST_MOVIE_POSTER_OPTION); export const setListMovieOverviewOption = createAction(SET_LIST_MOVIE_OVERVIEW_OPTION); -export const addNetImportExclusions = createThunk(ADD_NET_IMPORT_EXCLUSIONS); +export const addImportExclusions = createThunk(ADD_IMPORT_EXCLUSIONS); export const setAddMovieValue = createAction(SET_ADD_MOVIE_VALUE, (payload) => { return { @@ -339,8 +429,10 @@ export const actionHandlers = handleThunks({ ...otherPayload } = payload; + const includeRecommendations = getState().discoverMovie.options.includeRecommendations; + const promise = createAjaxRequest({ - url: '/movies/discover', + url: `/importlist/movie?includeRecommendations=${includeRecommendations}`, data: otherPayload, traditional: true }).request; @@ -392,7 +484,8 @@ export const actionHandlers = handleThunks({ dispatch(batchActions([ updateItem({ section: 'movies', ...data }), - removeItem({ section: 'discoverMovie', ...itemToUpdate }), + itemToUpdate.lists.length === 0 ? removeItem({ section: 'discoverMovie', ...itemToUpdate }) : + updateItem({ section: 'discoverMovie', ...itemToUpdate, isExisting: true }), set({ section, @@ -476,7 +569,7 @@ export const actionHandlers = handleThunks({ }); }, - [ADD_NET_IMPORT_EXCLUSIONS]: function(getState, payload, dispatch) { + [ADD_IMPORT_EXCLUSIONS]: function(getState, payload, dispatch) { const ids = payload.ids; const items = getState().discoverMovie.items; @@ -496,14 +589,14 @@ export const actionHandlers = handleThunks({ }, []); const promise = createAjaxRequest({ - url: '/exclusions', + url: '/exclusions/bulk', method: 'POST', data: JSON.stringify(exclusions) }).request; promise.done((data) => { dispatch(batchActions([ - ...data.map((item) => updateItem({ section: 'settings.netImportExclusions', ...item })), + ...data.map((item) => updateItem({ section: 'settings.importExclusions', ...item })), ...data.map((item) => updateItem({ section, id: item.tmdbId, isExcluded: true })), @@ -550,6 +643,18 @@ export const reducers = createHandleActions({ return Object.assign({}, state, { view: payload.view }); }, + [SET_LIST_MOVIE_OPTION]: function(state, { payload }) { + const discoveryMovieOptions = state.options; + + return { + ...state, + options: { + ...discoveryMovieOptions, + ...payload + } + }; + }, + [SET_LIST_MOVIE_TABLE_OPTION]: createSetTableOptionReducer(section), [SET_LIST_MOVIE_POSTER_OPTION]: function(state, { payload }) { diff --git a/frontend/src/Store/Actions/settingsActions.js b/frontend/src/Store/Actions/settingsActions.js index eb0fe46b6..e15766321 100644 --- a/frontend/src/Store/Actions/settingsActions.js +++ b/frontend/src/Store/Actions/settingsActions.js @@ -7,6 +7,9 @@ import delayProfiles from './Settings/delayProfiles'; import downloadClientOptions from './Settings/downloadClientOptions'; import downloadClients from './Settings/downloadClients'; import general from './Settings/general'; +import importExclusions from './Settings/importExclusions'; +import importListOptions from './Settings/importListOptions'; +import importLists from './Settings/importLists'; import indexerOptions from './Settings/indexerOptions'; import indexers from './Settings/indexers'; import languages from './Settings/languages'; @@ -15,9 +18,6 @@ import metadata from './Settings/metadata'; import metadataOptions from './Settings/metadataOptions'; import naming from './Settings/naming'; import namingExamples from './Settings/namingExamples'; -import netImportExclusions from './Settings/netImportExclusions'; -import netImportOptions from './Settings/netImportOptions'; -import netImports from './Settings/netImports'; import notifications from './Settings/notifications'; import qualityDefinitions from './Settings/qualityDefinitions'; import qualityProfiles from './Settings/qualityProfiles'; @@ -34,9 +34,9 @@ export * from './Settings/general'; export * from './Settings/indexerOptions'; export * from './Settings/indexers'; export * from './Settings/languages'; -export * from './Settings/netImportExclusions'; -export * from './Settings/netImportOptions'; -export * from './Settings/netImports'; +export * from './Settings/importExclusions'; +export * from './Settings/importListOptions'; +export * from './Settings/importLists'; export * from './Settings/mediaManagement'; export * from './Settings/metadata'; export * from './Settings/metadataOptions'; @@ -69,9 +69,9 @@ export const defaultState = { indexerOptions: indexerOptions.defaultState, indexers: indexers.defaultState, languages: languages.defaultState, - netImportExclusions: netImportExclusions.defaultState, - netImportOptions: netImportOptions.defaultState, - netImports: netImports.defaultState, + importExclusions: importExclusions.defaultState, + importListOptions: importListOptions.defaultState, + importLists: importLists.defaultState, mediaManagement: mediaManagement.defaultState, metadata: metadata.defaultState, metadataOptions: metadataOptions.defaultState, @@ -112,9 +112,9 @@ export const actionHandlers = handleThunks({ ...indexerOptions.actionHandlers, ...indexers.actionHandlers, ...languages.actionHandlers, - ...netImportExclusions.actionHandlers, - ...netImportOptions.actionHandlers, - ...netImports.actionHandlers, + ...importExclusions.actionHandlers, + ...importListOptions.actionHandlers, + ...importLists.actionHandlers, ...mediaManagement.actionHandlers, ...metadata.actionHandlers, ...metadataOptions.actionHandlers, @@ -146,9 +146,9 @@ export const reducers = createHandleActions({ ...indexerOptions.reducers, ...indexers.reducers, ...languages.reducers, - ...netImportExclusions.reducers, - ...netImportOptions.reducers, - ...netImports.reducers, + ...importExclusions.reducers, + ...importListOptions.reducers, + ...importLists.reducers, ...mediaManagement.reducers, ...metadata.reducers, ...metadataOptions.reducers, diff --git a/frontend/src/Store/Selectors/createExclusionMovieSelector.js b/frontend/src/Store/Selectors/createExclusionMovieSelector.js index 12adfd854..20365e9b5 100644 --- a/frontend/src/Store/Selectors/createExclusionMovieSelector.js +++ b/frontend/src/Store/Selectors/createExclusionMovieSelector.js @@ -4,9 +4,9 @@ import { createSelector } from 'reselect'; function createExclusionMovieSelector() { return createSelector( (state, { tmdbId }) => tmdbId, - (state) => state.settings.netImportExclusions, - (tmdbId, netImportExclusions) => { - return _.some(netImportExclusions.items, { tmdbId }); + (state) => state.settings.importExclusions, + (tmdbId, importExclusions) => { + return _.some(importExclusions.items, { tmdbId }); } ); } diff --git a/frontend/src/Store/Selectors/createImportListSelector.js b/frontend/src/Store/Selectors/createImportListSelector.js new file mode 100644 index 000000000..6f365aed5 --- /dev/null +++ b/frontend/src/Store/Selectors/createImportListSelector.js @@ -0,0 +1,12 @@ +import { createSelector } from 'reselect'; + +function createImportListSelector() { + return createSelector( + (state) => state.settings.importLists.items, + (lists) => { + return lists; + } + ); +} + +export default createImportListSelector; diff --git a/frontend/src/Store/Selectors/createMovieCollectionListSelector.js b/frontend/src/Store/Selectors/createMovieCollectionListSelector.js index d8d700fdd..6db80a118 100644 --- a/frontend/src/Store/Selectors/createMovieCollectionListSelector.js +++ b/frontend/src/Store/Selectors/createMovieCollectionListSelector.js @@ -4,9 +4,9 @@ import { createSelector } from 'reselect'; function createMovieCollectionListSelector() { return createSelector( (state, { tmdbId }) => tmdbId, - (state) => state.settings.netImports.items, - (tmdbId, netImports) => { - const netImportIds = _.reduce(netImports, (acc, list) => { + (state) => state.settings.importLists.items, + (tmdbId, importLists) => { + const importListIds = _.reduce(importLists, (acc, list) => { if (list.implementation === 'TMDbCollectionImport') { const collectionIdField = list.fields.find((field) => { return field.name === 'collectionId'; @@ -21,11 +21,11 @@ function createMovieCollectionListSelector() { return acc; }, []); - if (netImportIds.length === 0) { + if (importListIds.length === 0) { return undefined; } - return netImportIds[0]; + return importListIds[0]; } ); } diff --git a/frontend/src/Store/Selectors/createMovieCreditListSelector.js b/frontend/src/Store/Selectors/createMovieCreditListSelector.js index a98b1728c..51764b379 100644 --- a/frontend/src/Store/Selectors/createMovieCreditListSelector.js +++ b/frontend/src/Store/Selectors/createMovieCreditListSelector.js @@ -4,9 +4,9 @@ import { createSelector } from 'reselect'; function createMovieCreditListSelector() { return createSelector( (state, { tmdbId }) => tmdbId, - (state) => state.settings.netImports.items, - (tmdbId, netImports) => { - const netImportIds = _.reduce(netImports, (acc, list) => { + (state) => state.settings.importLists.items, + (tmdbId, importLists) => { + const importListIds = _.reduce(importLists, (acc, list) => { if (list.implementation === 'TMDbPersonImport') { const personIdField = list.fields.find((field) => { return field.name === 'personId'; @@ -21,14 +21,14 @@ function createMovieCreditListSelector() { return acc; }, []); - let netImportId = 0; + let importListId = 0; - if (netImportIds.length > 0) { - netImportId = netImportIds[0].id; + if (importListIds.length > 0) { + importListId = importListIds[0].id; } return { - netImportId + importListId }; } ); diff --git a/frontend/src/Store/Selectors/createProfileInUseSelector.js b/frontend/src/Store/Selectors/createProfileInUseSelector.js index e414d68ba..7b2e4d169 100644 --- a/frontend/src/Store/Selectors/createProfileInUseSelector.js +++ b/frontend/src/Store/Selectors/createProfileInUseSelector.js @@ -6,7 +6,7 @@ function createProfileInUseSelector(profileProp) { return createSelector( (state, { id }) => id, createAllMoviesSelector(), - (state) => state.settings.netImports.items, + (state) => state.settings.importLists.items, (id, movies, lists) => { if (!id) { return false; diff --git a/src/NzbDrone.Api/Config/NetImportConfigModule.cs b/src/NzbDrone.Api/Config/NetImportConfigModule.cs index 3c1ce926c..87787a6cb 100644 --- a/src/NzbDrone.Api/Config/NetImportConfigModule.cs +++ b/src/NzbDrone.Api/Config/NetImportConfigModule.cs @@ -3,18 +3,18 @@ using Radarr.Http.Validation; namespace NzbDrone.Api.Config { - public class NetImportConfigModule : NzbDroneConfigModule + public class ImportListConfigModule : NzbDroneConfigModule { - public NetImportConfigModule(IConfigService configService) + public ImportListConfigModule(IConfigService configService) : base(configService) { - SharedValidator.RuleFor(c => c.NetImportSyncInterval) - .IsValidNetImportSyncInterval(); + SharedValidator.RuleFor(c => c.ImportListSyncInterval) + .IsValidImportListSyncInterval(); } - protected override NetImportConfigResource ToResource(IConfigService model) + protected override ImportListConfigResource ToResource(IConfigService model) { - return NetImportConfigResourceMapper.ToResource(model); + return ImportListConfigResourceMapper.ToResource(model); } } } diff --git a/src/NzbDrone.Api/Config/NetImportConfigResource.cs b/src/NzbDrone.Api/Config/NetImportConfigResource.cs index dba6ec52f..77443dcaa 100644 --- a/src/NzbDrone.Api/Config/NetImportConfigResource.cs +++ b/src/NzbDrone.Api/Config/NetImportConfigResource.cs @@ -3,20 +3,20 @@ using Radarr.Http.REST; namespace NzbDrone.Api.Config { - public class NetImportConfigResource : RestResource + public class ImportListConfigResource : RestResource { - public int NetImportSyncInterval { get; set; } + public int ImportListSyncInterval { get; set; } public string ListSyncLevel { get; set; } public string ImportExclusions { get; set; } } - public static class NetImportConfigResourceMapper + public static class ImportListConfigResourceMapper { - public static NetImportConfigResource ToResource(IConfigService model) + public static ImportListConfigResource ToResource(IConfigService model) { - return new NetImportConfigResource + return new ImportListConfigResource { - NetImportSyncInterval = model.NetImportSyncInterval, + ImportListSyncInterval = model.ImportListSyncInterval, ListSyncLevel = model.ListSyncLevel, ImportExclusions = model.ImportExclusions, }; diff --git a/src/NzbDrone.Api/Movies/FetchMovieListModule.cs b/src/NzbDrone.Api/Movies/FetchMovieListModule.cs deleted file mode 100644 index 8e12f1c8b..000000000 --- a/src/NzbDrone.Api/Movies/FetchMovieListModule.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Nancy; -using NzbDrone.Core.MediaCover; -using NzbDrone.Core.MetadataSource; -using NzbDrone.Core.NetImport; -using Radarr.Http; - -namespace NzbDrone.Api.Movies -{ - public class FetchMovieListModule : RadarrRestModule - { - private readonly IFetchNetImport _fetchNetImport; - private readonly ISearchForNewMovie _movieSearch; - - public FetchMovieListModule(IFetchNetImport netImport, ISearchForNewMovie movieSearch) - : base("/netimport/movies") - { - _fetchNetImport = netImport; - _movieSearch = movieSearch; - Get("/", x => Search()); - } - - private object Search() - { - var results = _fetchNetImport.FetchAndFilter((int)Request.Query.listId, false); - - List realResults = new List(); - - /*foreach (var movie in results) - { - var mapped = _movieSearch.MapMovieToTmdbMovie(movie); - - if (mapped != null) - { - realResults.Add(mapped); - } - }*/ - - return MapToResource(results); - } - - private static IEnumerable MapToResource(IEnumerable movies) - { - foreach (var currentSeries in movies) - { - var resource = currentSeries.ToResource(); - var poster = currentSeries.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster); - if (poster != null) - { - resource.RemotePoster = poster.Url; - } - - yield return resource; - } - } - } -} diff --git a/src/NzbDrone.Api/Movies/MovieBulkImportModule.cs b/src/NzbDrone.Api/Movies/MovieBulkImportModule.cs deleted file mode 100644 index eb3886c55..000000000 --- a/src/NzbDrone.Api/Movies/MovieBulkImportModule.cs +++ /dev/null @@ -1,187 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Nancy; -using NzbDrone.Common.Cache; -using NzbDrone.Common.Extensions; -using NzbDrone.Core.Datastore; -using NzbDrone.Core.MediaCover; -using NzbDrone.Core.MediaFiles; -using NzbDrone.Core.MediaFiles.MovieImport; -using NzbDrone.Core.MetadataSource; -using NzbDrone.Core.Movies; -using NzbDrone.Core.Parser; -using NzbDrone.Core.Profiles; -using NzbDrone.Core.RootFolders; -using Radarr.Http; - -namespace NzbDrone.Api.Movies -{ - public class UnmappedComparer : IComparer - { - public int Compare(UnmappedFolder a, UnmappedFolder b) - { - return a.Name.CompareTo(b.Name); - } - } - - public class MovieBulkImportModule : RadarrRestModule - { - private readonly ISearchForNewMovie _searchProxy; - private readonly IRootFolderService _rootFolderService; - private readonly IMakeImportDecision _importDecisionMaker; - private readonly IDiskScanService _diskScanService; - private readonly ICached _mappedMovies; - private readonly IParsingService _parsingService; - private readonly IProfileService _profileService; - private readonly IMovieService _movieService; - - public MovieBulkImportModule(ISearchForNewMovie searchProxy, - IRootFolderService rootFolderService, - IMakeImportDecision importDecisionMaker, - IDiskScanService diskScanService, - ICacheManager cacheManager, - IParsingService parsingService, - IProfileService profileService, - IMovieService movieService) - : base("/movies/bulkimport") - { - _searchProxy = searchProxy; - _rootFolderService = rootFolderService; - _importDecisionMaker = importDecisionMaker; - _diskScanService = diskScanService; - _mappedMovies = cacheManager.GetCache(GetType(), "mappedMoviesCache"); - _movieService = movieService; - _profileService = profileService; - _parsingService = parsingService; - Get("/", x => Search()); - } - - private object Search() - { - if (Request.Query.Id == 0) - { - //Todo error handling - } - - Profile tempProfile = _profileService.All().First(); - - RootFolder rootFolder = _rootFolderService.Get(Request.Query.Id, true); - - int page = Request.Query.page; - int per_page = Request.Query.per_page; - - int min = (page - 1) * per_page; - - int max = page * per_page; - - var unmapped = rootFolder.UnmappedFolders.OrderBy(f => f.Name).ToList(); - - int total_count = unmapped.Count; - - if (Request.Query.total_entries.HasValue) - { - total_count = Request.Query.total_entries; - } - - max = total_count >= max ? max : total_count; - - var paged = unmapped.GetRange(min, max - min); - - var mapped = paged.Select(f => - { - Core.Movies.Movie m = null; - - var mappedMovie = _mappedMovies.Find(f.Name); - - if (mappedMovie != null) - { - return mappedMovie; - } - - var parsedTitle = _parsingService.ParseMinimalPathMovieInfo(f.Name); - if (parsedTitle == null) - { - m = new Core.Movies.Movie - { - Title = f.Name.Replace(".", " ").Replace("-", " "), - Path = f.Path, - Profile = tempProfile - }; - } - else - { - parsedTitle.ImdbId = Parser.ParseImdbId(parsedTitle.SimpleReleaseTitle); - - m = new Core.Movies.Movie - { - Title = parsedTitle.MovieTitle, - Year = parsedTitle.Year, - ImdbId = parsedTitle.ImdbId, - Path = f.Path, - Profile = tempProfile - }; - } - - var files = _diskScanService.GetVideoFiles(f.Path); - - var decisions = _importDecisionMaker.GetImportDecisions(files.ToList(), m); - - var decision = decisions.Where(d => d.Approved && !d.Rejections.Any()).FirstOrDefault(); - - if (decision != null) - { - var local = decision.LocalMovie; - - m.MovieFile = new MovieFile - { - Path = local.Path, - Edition = local.Edition, - Quality = local.Quality, - MediaInfo = local.MediaInfo, - ReleaseGroup = local.ReleaseGroup, - RelativePath = f.Path.GetRelativePath(local.Path) - }; - } - - mappedMovie = _searchProxy.MapMovieToTmdbMovie(m); - - if (mappedMovie != null) - { - mappedMovie.Monitored = true; - - _mappedMovies.Set(f.Name, mappedMovie, TimeSpan.FromDays(2)); - - return mappedMovie; - } - - return null; - }); - - return new PagingResource - { - Page = page, - PageSize = per_page, - SortDirection = SortDirection.Ascending, - SortKey = Request.Query.sort_by, - TotalRecords = total_count - mapped.Where(m => m == null).Count(), - Records = MapToResource(mapped.Where(m => m != null)).ToList() - }; - } - - private static IEnumerable MapToResource(IEnumerable movies) - { - foreach (var currentMovie in movies) - { - var resource = currentMovie.ToResource(); - var poster = currentMovie.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster); - if (poster != null) - { - resource.RemotePoster = poster.Url; - } - - yield return resource; - } - } - } -} diff --git a/src/NzbDrone.Api/Movies/MovieDiscoverModule.cs b/src/NzbDrone.Api/Movies/MovieDiscoverModule.cs index ccb86b817..c9e9775f1 100644 --- a/src/NzbDrone.Api/Movies/MovieDiscoverModule.cs +++ b/src/NzbDrone.Api/Movies/MovieDiscoverModule.cs @@ -1,21 +1,21 @@ using System.Collections.Generic; using System.Linq; -using NzbDrone.Api.NetImport; +using NzbDrone.Api.ImportList; +using NzbDrone.Core.ImportLists; using NzbDrone.Core.MediaCover; using NzbDrone.Core.Movies; -using NzbDrone.Core.NetImport; using Radarr.Http; namespace NzbDrone.Api.Movies { public class MovieDiscoverModule : RadarrRestModule { - private readonly INetImportFactory _netImportFactory; + private readonly IImportListFactory _importListFactory; - public MovieDiscoverModule(INetImportFactory netImportFactory) + public MovieDiscoverModule(IImportListFactory importListFactory) : base("/movies/discover") { - _netImportFactory = netImportFactory; + _importListFactory = importListFactory; Get("/lists", x => GetLists()); Get("/{action?recommendations}", x => Search(x.action)); } @@ -29,11 +29,11 @@ namespace NzbDrone.Api.Movies private object GetLists() { - var lists = _netImportFactory.Discoverable(); + var lists = _importListFactory.Discoverable(); return lists.Select(definition => { - var resource = new NetImportResource(); + var resource = new ImportListResource(); resource.Id = definition.Definition.Id; resource.Name = definition.Definition.Name; diff --git a/src/NzbDrone.Api/NetImport/ImportExclusionsModule.cs b/src/NzbDrone.Api/NetImport/ImportExclusionsModule.cs index 7ecc04c06..2d94e69c8 100644 --- a/src/NzbDrone.Api/NetImport/ImportExclusionsModule.cs +++ b/src/NzbDrone.Api/NetImport/ImportExclusionsModule.cs @@ -1,15 +1,15 @@ using System.Collections.Generic; -using NzbDrone.Core.NetImport; -using NzbDrone.Core.NetImport.ImportExclusions; +using NzbDrone.Core.ImportLists; +using NzbDrone.Core.ImportLists.ImportExclusions; using Radarr.Http; -namespace NzbDrone.Api.NetImport +namespace NzbDrone.Api.ImportList { public class ImportExclusionsModule : RadarrRestModule { private readonly IImportExclusionsService _exclusionService; - public ImportExclusionsModule(NetImportFactory netImportFactory, IImportExclusionsService exclusionService) + public ImportExclusionsModule(ImportListFactory importListFactory, IImportExclusionsService exclusionService) : base("exclusions") { _exclusionService = exclusionService; diff --git a/src/NzbDrone.Api/NetImport/ImportExclusionsResource.cs b/src/NzbDrone.Api/NetImport/ImportExclusionsResource.cs index e2a3eff22..fb984eebb 100644 --- a/src/NzbDrone.Api/NetImport/ImportExclusionsResource.cs +++ b/src/NzbDrone.Api/NetImport/ImportExclusionsResource.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -namespace NzbDrone.Api.NetImport +namespace NzbDrone.Api.ImportList { public class ImportExclusionsResource : ProviderResource { @@ -13,7 +13,7 @@ namespace NzbDrone.Api.NetImport public static class ImportExclusionsResourceMapper { - public static ImportExclusionsResource ToResource(this Core.NetImport.ImportExclusions.ImportExclusion model) + public static ImportExclusionsResource ToResource(this Core.ImportLists.ImportExclusions.ImportExclusion model) { if (model == null) { @@ -29,14 +29,14 @@ namespace NzbDrone.Api.NetImport }; } - public static List ToResource(this IEnumerable exclusions) + public static List ToResource(this IEnumerable exclusions) { return exclusions.Select(ToResource).ToList(); } - public static Core.NetImport.ImportExclusions.ImportExclusion ToModel(this ImportExclusionsResource resource) + public static Core.ImportLists.ImportExclusions.ImportExclusion ToModel(this ImportExclusionsResource resource) { - return new Core.NetImport.ImportExclusions.ImportExclusion + return new Core.ImportLists.ImportExclusions.ImportExclusion { TmdbId = resource.TmdbId, MovieTitle = resource.MovieTitle, diff --git a/src/NzbDrone.Api/NetImport/ListImportModule.cs b/src/NzbDrone.Api/NetImport/ListImportModule.cs deleted file mode 100644 index 86d3aea24..000000000 --- a/src/NzbDrone.Api/NetImport/ListImportModule.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Nancy; -using Nancy.Extensions; -using NzbDrone.Api.Movies; -using NzbDrone.Core.MetadataSource; -using NzbDrone.Core.Movies; -using Radarr.Http.Extensions; - -namespace NzbDrone.Api.NetImport -{ - public class ListImportModule : NzbDroneApiModule - { - private readonly IAddMovieService _addMovieService; - private readonly ISearchForNewMovie _movieSearch; - - public ListImportModule(IAddMovieService addMovieService, ISearchForNewMovie movieSearch) - : base("/movie/import") - { - _addMovieService = addMovieService; - _movieSearch = movieSearch; - Put("/", movie => SaveAll()); - } - - private object SaveAll() - { - var resources = Request.Body.FromJson>(); - - var movies = resources.Select(movieResource => _movieSearch.MapMovieToTmdbMovie(movieResource.ToModel())).Where(m => m != null).DistinctBy(m => m.TmdbId).ToList(); - - return ResponseWithCode(_addMovieService.AddMovies(movies).ToResource(), HttpStatusCode.Accepted); - } - } -} diff --git a/src/NzbDrone.Api/NetImport/NetImportModule.cs b/src/NzbDrone.Api/NetImport/NetImportModule.cs index a87384fcd..4798e7b33 100644 --- a/src/NzbDrone.Api/NetImport/NetImportModule.cs +++ b/src/NzbDrone.Api/NetImport/NetImportModule.cs @@ -1,14 +1,14 @@ using FluentValidation; -using NzbDrone.Core.NetImport; +using NzbDrone.Core.ImportLists; using NzbDrone.Core.Validation; using NzbDrone.Core.Validation.Paths; -namespace NzbDrone.Api.NetImport +namespace NzbDrone.Api.ImportList { - public class NetImportModule : ProviderModuleBase + public class ImportListModule : ProviderModuleBase { - public NetImportModule(NetImportFactory netImportFactory, ProfileExistsValidator profileExistsValidator) - : base(netImportFactory, "netimport") + public ImportListModule(ImportListFactory importListFactory, ProfileExistsValidator profileExistsValidator) + : base(importListFactory, "netimport") { PostValidator.RuleFor(c => c.RootFolderPath).IsValidPath(); PostValidator.RuleFor(c => c.MinimumAvailability).NotNull(); @@ -16,7 +16,7 @@ namespace NzbDrone.Api.NetImport SharedValidator.RuleFor(c => c.ProfileId).SetValidator(profileExistsValidator); } - protected override void MapToResource(NetImportResource resource, NetImportDefinition definition) + protected override void MapToResource(ImportListResource resource, ImportListDefinition definition) { base.MapToResource(resource, definition); @@ -29,7 +29,7 @@ namespace NzbDrone.Api.NetImport resource.Tags = definition.Tags; } - protected override void MapToModel(NetImportDefinition definition, NetImportResource resource) + protected override void MapToModel(ImportListDefinition definition, ImportListResource resource) { base.MapToModel(definition, resource); @@ -42,7 +42,7 @@ namespace NzbDrone.Api.NetImport definition.Tags = resource.Tags; } - protected override void Validate(NetImportDefinition definition, bool includeWarnings) + protected override void Validate(ImportListDefinition definition, bool includeWarnings) { if (!definition.Enable) { diff --git a/src/NzbDrone.Api/NetImport/NetImportResource.cs b/src/NzbDrone.Api/NetImport/NetImportResource.cs index 76716eaa9..8f211b432 100644 --- a/src/NzbDrone.Api/NetImport/NetImportResource.cs +++ b/src/NzbDrone.Api/NetImport/NetImportResource.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using NzbDrone.Core.Movies; -namespace NzbDrone.Api.NetImport +namespace NzbDrone.Api.ImportList { - public class NetImportResource : ProviderResource + public class ImportListResource : ProviderResource { public bool Enabled { get; set; } public bool EnableAuto { get; set; } diff --git a/src/NzbDrone.Api/swagger.json b/src/NzbDrone.Api/swagger.json index 8ca95344a..e57a1d3f5 100644 --- a/src/NzbDrone.Api/swagger.json +++ b/src/NzbDrone.Api/swagger.json @@ -198,7 +198,7 @@ } }, { - "name": "addNetImportExclusion", + "name": "addImportExclusion", "in": "query", "schema": { "type": "boolean" diff --git a/src/NzbDrone.Common/Cloud/RadarrCloudRequestBuilder.cs b/src/NzbDrone.Common/Cloud/RadarrCloudRequestBuilder.cs index ce22ce009..7801d0ca0 100644 --- a/src/NzbDrone.Common/Cloud/RadarrCloudRequestBuilder.cs +++ b/src/NzbDrone.Common/Cloud/RadarrCloudRequestBuilder.cs @@ -6,7 +6,6 @@ namespace NzbDrone.Common.Cloud { IHttpRequestBuilderFactory Services { get; } IHttpRequestBuilderFactory TMDB { get; } - IHttpRequestBuilderFactory TMDBSingle { get; } IHttpRequestBuilderFactory RadarrMetadata { get; } } @@ -21,17 +20,12 @@ namespace NzbDrone.Common.Cloud .SetHeader("Authorization", $"Bearer {AuthToken}") .CreateFactory(); - TMDBSingle = new HttpRequestBuilder("https://api.themoviedb.org/3/{route}") - .SetHeader("Authorization", $"Bearer {AuthToken}") - .CreateFactory(); - RadarrMetadata = new HttpRequestBuilder("https://radarrapi.servarr.com/v1/{route}") .CreateFactory(); } public IHttpRequestBuilderFactory Services { get; private set; } public IHttpRequestBuilderFactory TMDB { get; private set; } - public IHttpRequestBuilderFactory TMDBSingle { get; private set; } public IHttpRequestBuilderFactory RadarrMetadata { get; private set; } public string AuthToken => "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxYTczNzMzMDE5NjFkMDNmOTdmODUzYTg3NmRkMTIxMiIsInN1YiI6IjU4NjRmNTkyYzNhMzY4MGFiNjAxNzUzNCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.gh1BwogCCKOda6xj9FRMgAAj_RYKMMPC3oNlcBtlmwk"; diff --git a/src/NzbDrone.Common/Extensions/IEnumerableExtensions.cs b/src/NzbDrone.Common/Extensions/IEnumerableExtensions.cs index c9578a84e..deb75de1e 100644 --- a/src/NzbDrone.Common/Extensions/IEnumerableExtensions.cs +++ b/src/NzbDrone.Common/Extensions/IEnumerableExtensions.cs @@ -155,5 +155,10 @@ namespace NzbDrone.Common.Extensions { return string.Join(separator, source.Select(predicate)); } + + public static HashSet ToHashSet(this IEnumerable source, IEqualityComparer comparer = null) + { + return new HashSet(source, comparer); + } } } diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/178_new_list_serverFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/178_new_list_serverFixture.cs index 4d91eb5b3..f0a6c1c95 100644 --- a/src/NzbDrone.Core.Test/Datastore/Migration/178_new_list_serverFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/Migration/178_new_list_serverFixture.cs @@ -4,10 +4,10 @@ using FizzWare.NBuilder; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Datastore.Migration; -using NzbDrone.Core.NetImport.RadarrList; -using NzbDrone.Core.NetImport.RadarrList2.IMDbList; -using NzbDrone.Core.NetImport.RadarrList2.StevenLu; -using NzbDrone.Core.NetImport.StevenLu; +using NzbDrone.Core.ImportLists.RadarrList; +using NzbDrone.Core.ImportLists.RadarrList2.IMDbList; +using NzbDrone.Core.ImportLists.RadarrList2.StevenLu; +using NzbDrone.Core.ImportLists.StevenLu; using NzbDrone.Core.Test.Framework; namespace NzbDrone.Core.Test.Datastore.Migration diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/NetImportStatusCheckFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/NetImportStatusCheckFixture.cs index fdeff3ab7..f2d75a462 100644 --- a/src/NzbDrone.Core.Test/HealthCheck/Checks/NetImportStatusCheckFixture.cs +++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/NetImportStatusCheckFixture.cs @@ -3,26 +3,26 @@ using System.Collections.Generic; using Moq; using NUnit.Framework; using NzbDrone.Core.HealthCheck.Checks; +using NzbDrone.Core.ImportLists; using NzbDrone.Core.Localization; -using NzbDrone.Core.NetImport; using NzbDrone.Core.Test.Framework; namespace NzbDrone.Core.Test.HealthCheck.Checks { [TestFixture] - public class NetImportStatusCheckFixture : CoreTest + public class ImportListStatusCheckFixture : CoreTest { - private List _lists = new List(); - private List _blockedLists = new List(); + private List _lists = new List(); + private List _blockedLists = new List(); [SetUp] public void SetUp() { - Mocker.GetMock() + Mocker.GetMock() .Setup(v => v.GetAvailableProviders()) .Returns(_lists); - Mocker.GetMock() + Mocker.GetMock() .Setup(v => v.GetBlockedProviders()) .Returns(_blockedLists); @@ -31,19 +31,19 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks .Returns("Some Warning Message"); } - private Mock GivenList(int i, double backoffHours, double failureHours) + private Mock GivenList(int i, double backoffHours, double failureHours) { var id = i; - var mockList = new Mock(); - mockList.SetupGet(s => s.Definition).Returns(new NetImportDefinition { Id = id }); + var mockList = new Mock(); + mockList.SetupGet(s => s.Definition).Returns(new ImportListDefinition { Id = id }); mockList.SetupGet(s => s.EnableAuto).Returns(true); _lists.Add(mockList.Object); if (backoffHours != 0.0) { - _blockedLists.Add(new NetImportStatus + _blockedLists.Add(new ImportListStatus { ProviderId = id, InitialFailure = DateTime.UtcNow.AddHours(-failureHours), diff --git a/src/NzbDrone.Core.Test/NetImport/CouchPotato/CouchPotatoParserFixture.cs b/src/NzbDrone.Core.Test/ImportListTests/CouchPotato/CouchPotatoParserFixture.cs similarity index 73% rename from src/NzbDrone.Core.Test/NetImport/CouchPotato/CouchPotatoParserFixture.cs rename to src/NzbDrone.Core.Test/ImportListTests/CouchPotato/CouchPotatoParserFixture.cs index 25b3811dd..72c50abcf 100644 --- a/src/NzbDrone.Core.Test/NetImport/CouchPotato/CouchPotatoParserFixture.cs +++ b/src/NzbDrone.Core.Test/ImportListTests/CouchPotato/CouchPotatoParserFixture.cs @@ -3,20 +3,20 @@ using System.Text; using FluentAssertions; using NUnit.Framework; using NzbDrone.Common.Http; -using NzbDrone.Core.NetImport; -using NzbDrone.Core.NetImport.CouchPotato; +using NzbDrone.Core.ImportLists; +using NzbDrone.Core.ImportLists.CouchPotato; using NzbDrone.Core.Test.Framework; -namespace NzbDrone.Core.Test.NetImport.CouchPotato +namespace NzbDrone.Core.Test.ImportList.CouchPotato { public class CouchPotatoTest : CoreTest { - private NetImportResponse CreateResponse(string url, string content) + private ImportListResponse CreateResponse(string url, string content) { var httpRequest = new HttpRequest(url); var httpResponse = new HttpResponse(httpRequest, new HttpHeader(), Encoding.UTF8.GetBytes(content)); - return new NetImportResponse(new NetImportRequest(httpRequest), httpResponse); + return new ImportListResponse(new ImportListRequest(httpRequest), httpResponse); } [Test] diff --git a/src/NzbDrone.Core.Test/ImportListTests/FetchAndParseImportListServiceFixture.cs b/src/NzbDrone.Core.Test/ImportListTests/FetchAndParseImportListServiceFixture.cs new file mode 100644 index 000000000..0a5c67d3f --- /dev/null +++ b/src/NzbDrone.Core.Test/ImportListTests/FetchAndParseImportListServiceFixture.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Core.ImportLists; +using NzbDrone.Core.ImportLists.ImportListMovies; +using NzbDrone.Core.MetadataSource; +using NzbDrone.Core.Movies; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.ImportListTests +{ + [TestFixture] + public class FetchAndParseImportListServiceFixture : CoreTest + { + private List _importLists; + private List _blockedLists; + private List _listMovies; + + [SetUp] + public void Setup() + { + _importLists = new List(); + _blockedLists = new List(); + + Mocker.GetMock() + .Setup(v => v.Enabled()) + .Returns(_importLists); + + Mocker.GetMock() + .Setup(v => v.GetBlockedProviders()) + .Returns(_blockedLists); + + _listMovies = Builder.CreateListOfSize(5) + .Build().ToList(); + + Mocker.GetMock() + .Setup(v => v.MapMovieToTmdbMovie(It.IsAny())) + .Returns(m => new Movie { TmdbId = m.TmdbId }); + } + + private void GivenList(int id, bool enabled, bool enabledAuto, ImportListFetchResult fetchResult) + { + CreateListResult(id, enabled, enabledAuto, fetchResult); + } + + private Mock CreateListResult(int id, bool enabled, bool enabledAuto, ImportListFetchResult fetchResult) + { + var importListDefinition = new ImportListDefinition { Id = id, EnableAuto = enabledAuto }; + + var mockImportList = new Mock(); + mockImportList.SetupGet(s => s.Definition).Returns(importListDefinition); + mockImportList.SetupGet(s => s.Enabled).Returns(enabled); + mockImportList.SetupGet(s => s.EnableAuto).Returns(enabledAuto); + mockImportList.Setup(s => s.Fetch()).Returns(fetchResult); + + _importLists.Add(mockImportList.Object); + + return mockImportList; + } + + private void GivenBlockedList(int id) + { + _blockedLists.Add(new ImportListStatus { ProviderId = id, DisabledTill = DateTime.UtcNow.AddDays(2) }); + } + + [Test] + public void should_return_failure_if_blocked_list() + { + var fetchResult = new ImportListFetchResult(); + GivenList(1, true, true, fetchResult); + GivenBlockedList(1); + + var listResult = Subject.Fetch(); + listResult.AnyFailure.Should().BeTrue(); + } + + [Test] + public void should_return_failure_if_one_blocked_list_one_good_list() + { + var fetchResult1 = new ImportListFetchResult(); + GivenList(1, true, true, fetchResult1); + GivenBlockedList(1); + + var fetchResult2 = new ImportListFetchResult { Movies = _listMovies, AnyFailure = true }; + GivenList(2, true, true, fetchResult2); + + var listResult = Subject.Fetch(); + listResult.AnyFailure.Should().BeTrue(); + } + + [Test] + public void should_return_failure_if_single_list_fails() + { + var fetchResult = new ImportListFetchResult { Movies = _listMovies, AnyFailure = true }; + GivenList(1, true, true, fetchResult); + + var listResult = Subject.Fetch(); + listResult.AnyFailure.Should().BeTrue(); + } + + [Test] + public void should_return_failure_if_any_list_fails() + { + var fetchResult1 = new ImportListFetchResult { Movies = _listMovies, AnyFailure = true }; + GivenList(1, true, true, fetchResult1); + var fetchResult2 = new ImportListFetchResult { Movies = _listMovies, AnyFailure = false }; + GivenList(2, true, true, fetchResult2); + + var listResult = Subject.Fetch(); + listResult.AnyFailure.Should().BeTrue(); + } + + [Test] + public void should_return_early_if_no_available_lists() + { + var listResult = Subject.Fetch(); + + Mocker.GetMock() + .Verify(v => v.GetBlockedProviders(), Times.Never()); + + listResult.Movies.Count.Should().Be(0); + listResult.AnyFailure.Should().BeFalse(); + } + + [Test] + public void should_store_movies_if_list_doesnt_fail() + { + var listId = 1; + var fetchResult = new ImportListFetchResult { Movies = _listMovies, AnyFailure = false }; + GivenList(listId, true, true, fetchResult); + + var listResult = Subject.Fetch(); + listResult.AnyFailure.Should().BeFalse(); + + Mocker.GetMock() + .Verify(v => v.SyncMoviesForList(It.IsAny>(), listId), Times.Once()); + } + + [Test] + public void should_not_store_movies_if_list_fails() + { + var listId = 1; + var fetchResult = new ImportListFetchResult { Movies = _listMovies, AnyFailure = true }; + GivenList(listId, true, true, fetchResult); + + var listResult = Subject.Fetch(); + listResult.AnyFailure.Should().BeTrue(); + + Mocker.GetMock() + .Verify(v => v.SyncMoviesForList(It.IsAny>(), listId), Times.Never()); + } + + [Test] + public void should_only_store_movies_for_lists_that_dont_fail() + { + var passedListId = 1; + var fetchResult1 = new ImportListFetchResult { Movies = _listMovies, AnyFailure = false }; + GivenList(passedListId, true, true, fetchResult1); + var failedListId = 2; + var fetchResult2 = new ImportListFetchResult { Movies = _listMovies, AnyFailure = true }; + GivenList(failedListId, true, true, fetchResult2); + + var listResult = Subject.Fetch(); + listResult.AnyFailure.Should().BeTrue(); + + Mocker.GetMock() + .Verify(v => v.SyncMoviesForList(It.IsAny>(), passedListId), Times.Once()); + } + + [Test] + public void should_return_all_results_for_all_lists() + { + var passedListId = 1; + var fetchResult1 = new ImportListFetchResult { Movies = _listMovies, AnyFailure = false }; + GivenList(passedListId, true, true, fetchResult1); + var failedListId = 2; + var fetchResult2 = new ImportListFetchResult { Movies = _listMovies, AnyFailure = false }; + GivenList(failedListId, true, true, fetchResult2); + + var listResult = Subject.Fetch(); + listResult.AnyFailure.Should().BeFalse(); + listResult.Movies.Count.Should().Be(10); + } + } +} diff --git a/src/NzbDrone.Core.Test/NetImport/NetImportStatusServiceFixture.cs b/src/NzbDrone.Core.Test/ImportListTests/ImportListStatusServiceFixture.cs similarity index 61% rename from src/NzbDrone.Core.Test/NetImport/NetImportStatusServiceFixture.cs rename to src/NzbDrone.Core.Test/ImportListTests/ImportListStatusServiceFixture.cs index 460faf064..5374665c2 100644 --- a/src/NzbDrone.Core.Test/NetImport/NetImportStatusServiceFixture.cs +++ b/src/NzbDrone.Core.Test/ImportListTests/ImportListStatusServiceFixture.cs @@ -4,12 +4,12 @@ using FluentAssertions; using Moq; using NUnit.Framework; using NzbDrone.Common.EnvironmentInfo; -using NzbDrone.Core.NetImport; +using NzbDrone.Core.ImportLists; using NzbDrone.Core.Test.Framework; -namespace NzbDrone.Core.Test.NetImport +namespace NzbDrone.Core.Test.ImportList { - public class NetImportStatusServiceFixture : CoreTest + public class ImportListStatusServiceFixture : CoreTest { private DateTime _epoch; @@ -23,33 +23,33 @@ namespace NzbDrone.Core.Test.NetImport .Returns(_epoch - TimeSpan.FromHours(1)); } - private void WithStatus(NetImportStatus status) + private void WithStatus(ImportListStatus status) { - Mocker.GetMock() + Mocker.GetMock() .Setup(v => v.FindByProviderId(1)) .Returns(status); - Mocker.GetMock() + Mocker.GetMock() .Setup(v => v.All()) .Returns(new[] { status }); } private void VerifyUpdate() { - Mocker.GetMock() - .Verify(v => v.Upsert(It.IsAny()), Times.Once()); + Mocker.GetMock() + .Verify(v => v.Upsert(It.IsAny()), Times.Once()); } private void VerifyNoUpdate() { - Mocker.GetMock() - .Verify(v => v.Upsert(It.IsAny()), Times.Never()); + Mocker.GetMock() + .Verify(v => v.Upsert(It.IsAny()), Times.Never()); } [Test] public void should_cancel_backoff_on_success() { - WithStatus(new NetImportStatus { EscalationLevel = 2 }); + WithStatus(new ImportListStatus { EscalationLevel = 2 }); Subject.RecordSuccess(1); @@ -62,7 +62,7 @@ namespace NzbDrone.Core.Test.NetImport [Test] public void should_not_store_update_if_already_okay() { - WithStatus(new NetImportStatus { EscalationLevel = 0 }); + WithStatus(new ImportListStatus { EscalationLevel = 0 }); Subject.RecordSuccess(1); diff --git a/src/NzbDrone.Core.Test/NetImport/NetImportSearchServiceFixture.cs b/src/NzbDrone.Core.Test/ImportListTests/ImportListSyncServiceFixture.cs similarity index 54% rename from src/NzbDrone.Core.Test/NetImport/NetImportSearchServiceFixture.cs rename to src/NzbDrone.Core.Test/ImportListTests/ImportListSyncServiceFixture.cs index dd89aee1c..3e937b3c0 100644 --- a/src/NzbDrone.Core.Test/NetImport/NetImportSearchServiceFixture.cs +++ b/src/NzbDrone.Core.Test/ImportListTests/ImportListSyncServiceFixture.cs @@ -4,33 +4,47 @@ using FizzWare.NBuilder; using Moq; using NUnit.Framework; using NzbDrone.Core.Configuration; -using NzbDrone.Core.MetadataSource; +using NzbDrone.Core.ImportLists; +using NzbDrone.Core.ImportLists.ImportExclusions; +using NzbDrone.Core.ImportLists.ImportListMovies; using NzbDrone.Core.Movies; -using NzbDrone.Core.NetImport; -using NzbDrone.Core.NetImport.ImportExclusions; using NzbDrone.Core.Test.Framework; -namespace NzbDrone.Core.Test.NetImport +namespace NzbDrone.Core.Test.ImportList { [TestFixture] - public class NetImportSearchServiceFixture : CoreTest + public class ImportListSyncServiceFixture : CoreTest { - private NetImportFetchResult _netImport1Fetch; - private NetImportFetchResult _netImport2Fetch; - private List _moviesList1; - private List _moviesList2; - private List _netImports; - private NetImportSyncCommand _command; + private ImportListFetchResult _importListFetch; + private List _list1Movies; + private List _list2Movies; + + private List _existingMovies; + private List _importLists; + private ImportListSyncCommand _commandAll; + private ImportListSyncCommand _commandSingle; [SetUp] public void Setup() { - _netImports = new List(); + _importLists = new List(); + + _list1Movies = Builder.CreateListOfSize(5) + .Build().ToList(); - _moviesList1 = Builder.CreateListOfSize(5) + _existingMovies = Builder.CreateListOfSize(3) + .TheFirst(1) + .With(s => s.TmdbId = 6) + .With(s => s.ImdbId = "6") + .TheNext(1) + .With(s => s.TmdbId = 7) + .With(s => s.ImdbId = "7") + .TheNext(1) + .With(s => s.TmdbId = 8) + .With(s => s.ImdbId = "8") .Build().ToList(); - _moviesList2 = Builder.CreateListOfSize(3) + _list2Movies = Builder.CreateListOfSize(3) .TheFirst(1) .With(s => s.TmdbId = 6) .With(s => s.ImdbId = "6") @@ -42,43 +56,45 @@ namespace NzbDrone.Core.Test.NetImport .With(s => s.ImdbId = "8") .Build().ToList(); - _netImport1Fetch = new NetImportFetchResult + _importListFetch = new ImportListFetchResult { - Movies = _moviesList1, + Movies = _list1Movies, AnyFailure = false }; - _netImport2Fetch = new NetImportFetchResult + _commandAll = new ImportListSyncCommand { - Movies = _moviesList2, - AnyFailure = false }; - _command = new NetImportSyncCommand + _commandSingle = new ImportListSyncCommand { - ListId = 0 + DefinitionId = 1 }; - Mocker.GetMock() - .Setup(v => v.GetAvailableProviders()) - .Returns(_netImports); + Mocker.GetMock() + .Setup(v => v.Enabled()) + .Returns(_importLists); Mocker.GetMock() - .Setup(v => v.IsMovieExcluded(It.IsAny())) - .Returns(false); - - Mocker.GetMock() - .Setup(v => v.MapMovieToTmdbMovie(It.IsAny())) - .Returns((Movie movie) => movie); + .Setup(v => v.GetAllExclusions()) + .Returns(new List()); Mocker.GetMock() .Setup(v => v.MovieExists(It.IsAny())) .Returns(false); + + Mocker.GetMock() + .Setup(v => v.AllMovieTmdbIds()) + .Returns(new List()); + + Mocker.GetMock() + .Setup(v => v.Fetch()) + .Returns(_importListFetch); } private void GivenListFailure() { - _netImport1Fetch.AnyFailure = true; + _importListFetch.AnyFailure = true; } private void GivenCleanLevel(string cleanLevel) @@ -88,29 +104,39 @@ namespace NzbDrone.Core.Test.NetImport .Returns(cleanLevel); } - private Mock GivenList(int i, bool enabledAuto, NetImportFetchResult fetchResult) + private void GivenList(int id, bool enabledAuto) + { + var importListDefinition = new ImportListDefinition { Id = id, EnableAuto = enabledAuto }; + + Mocker.GetMock() + .Setup(v => v.Get(id)) + .Returns(importListDefinition); + + CreateListResult(id, enabledAuto); + } + + private Mock CreateListResult(int id, bool enabledAuto) { - var id = i; + var importListDefinition = new ImportListDefinition { Id = id, EnableAuto = enabledAuto }; - var mockNetImport = new Mock(); - mockNetImport.SetupGet(s => s.Definition).Returns(new NetImportDefinition { Id = id, EnableAuto = enabledAuto }); - mockNetImport.SetupGet(s => s.Enabled).Returns(true); - mockNetImport.SetupGet(s => s.EnableAuto).Returns(enabledAuto); - mockNetImport.Setup(s => s.Fetch()).Returns(fetchResult); + var mockImportList = new Mock(); + mockImportList.SetupGet(s => s.Definition).Returns(importListDefinition); + mockImportList.SetupGet(s => s.Enabled).Returns(true); + mockImportList.SetupGet(s => s.EnableAuto).Returns(enabledAuto); - _netImports.Add(mockNetImport.Object); + _importLists.Add(mockImportList.Object); - return mockNetImport; + return mockImportList; } [Test] public void should_not_clean_library_if_config_value_disable() { - GivenList(1, true, _netImport1Fetch); - + _importListFetch.Movies.ForEach(m => m.ListId = 1); + GivenList(1, true); GivenCleanLevel("disabled"); - Subject.Execute(_command); + Subject.Execute(_commandAll); Mocker.GetMock() .Verify(v => v.GetAllMovies(), Times.Never()); @@ -122,15 +148,15 @@ namespace NzbDrone.Core.Test.NetImport [Test] public void should_log_only_on_clean_library_if_config_value_logonly() { - GivenList(1, true, _netImport1Fetch); - + _importListFetch.Movies.ForEach(m => m.ListId = 1); + GivenList(1, true); GivenCleanLevel("logOnly"); Mocker.GetMock() .Setup(v => v.GetAllMovies()) - .Returns(_moviesList2); + .Returns(_existingMovies); - Subject.Execute(_command); + Subject.Execute(_commandAll); Mocker.GetMock() .Verify(v => v.GetAllMovies(), Times.Once()); @@ -145,15 +171,15 @@ namespace NzbDrone.Core.Test.NetImport [Test] public void should_unmonitor_on_clean_library_if_config_value_keepAndUnmonitor() { - GivenList(1, true, _netImport1Fetch); - + _importListFetch.Movies.ForEach(m => m.ListId = 1); + GivenList(1, true); GivenCleanLevel("keepAndUnmonitor"); Mocker.GetMock() .Setup(v => v.GetAllMovies()) - .Returns(_moviesList2); + .Returns(_existingMovies); - Subject.Execute(_command); + Subject.Execute(_commandAll); Mocker.GetMock() .Verify(v => v.GetAllMovies(), Times.Once()); @@ -168,17 +194,17 @@ namespace NzbDrone.Core.Test.NetImport [Test] public void should_not_clean_on_clean_library_if_tmdb_match() { - _netImport1Fetch.Movies[0].TmdbId = 6; - - GivenList(1, true, _netImport1Fetch); + _importListFetch.Movies.ForEach(m => m.ListId = 1); + _importListFetch.Movies[0].TmdbId = 6; + GivenList(1, true); GivenCleanLevel("keepAndUnmonitor"); Mocker.GetMock() .Setup(v => v.GetAllMovies()) - .Returns(_moviesList2); + .Returns(_existingMovies); - Subject.Execute(_command); + Subject.Execute(_commandAll); Mocker.GetMock() .Verify(v => v.UpdateMovie(It.Is>(s => s.Count == 2 && s.All(m => !m.Monitored)), true), Times.Once()); @@ -187,18 +213,18 @@ namespace NzbDrone.Core.Test.NetImport [Test] public void should_fallback_to_imdbid_on_clean_library_if_tmdb_not_found() { - _netImport1Fetch.Movies[0].TmdbId = 0; - _netImport1Fetch.Movies[0].ImdbId = "6"; - - GivenList(1, true, _netImport1Fetch); + _importListFetch.Movies.ForEach(m => m.ListId = 1); + _importListFetch.Movies[0].TmdbId = 0; + _importListFetch.Movies[0].ImdbId = "6"; + GivenList(1, true); GivenCleanLevel("keepAndUnmonitor"); Mocker.GetMock() .Setup(v => v.GetAllMovies()) - .Returns(_moviesList2); + .Returns(_existingMovies); - Subject.Execute(_command); + Subject.Execute(_commandAll); Mocker.GetMock() .Verify(v => v.UpdateMovie(It.Is>(s => s.Count == 2 && s.All(m => !m.Monitored)), true), Times.Once()); @@ -207,15 +233,15 @@ namespace NzbDrone.Core.Test.NetImport [Test] public void should_delete_movies_not_files_on_clean_library_if_config_value_logonly() { - GivenList(1, true, _netImport1Fetch); - + _importListFetch.Movies.ForEach(m => m.ListId = 1); + GivenList(1, true); GivenCleanLevel("removeAndKeep"); Mocker.GetMock() .Setup(v => v.GetAllMovies()) - .Returns(_moviesList2); + .Returns(_existingMovies); - Subject.Execute(_command); + Subject.Execute(_commandAll); Mocker.GetMock() .Verify(v => v.GetAllMovies(), Times.Once()); @@ -233,15 +259,15 @@ namespace NzbDrone.Core.Test.NetImport [Test] public void should_delete_movies_and_files_on_clean_library_if_config_value_logonly() { - GivenList(1, true, _netImport1Fetch); - + _importListFetch.Movies.ForEach(m => m.ListId = 1); + GivenList(1, true); GivenCleanLevel("removeAndDelete"); Mocker.GetMock() .Setup(v => v.GetAllMovies()) - .Returns(_moviesList2); + .Returns(_existingMovies); - Subject.Execute(_command); + Subject.Execute(_commandAll); Mocker.GetMock() .Verify(v => v.GetAllMovies(), Times.Once()); @@ -259,12 +285,13 @@ namespace NzbDrone.Core.Test.NetImport [Test] public void should_not_clean_if_list_failures() { + _importListFetch.Movies.ForEach(m => m.ListId = 1); GivenListFailure(); - GivenList(1, true, _netImport1Fetch); + GivenList(1, true); GivenCleanLevel("disabled"); - Subject.Execute(_command); + Subject.Execute(_commandAll); Mocker.GetMock() .Verify(v => v.UpdateMovie(new List(), true), Times.Never()); @@ -273,11 +300,11 @@ namespace NzbDrone.Core.Test.NetImport [Test] public void should_add_new_movies_from_single_list_to_library() { - GivenList(1, true, _netImport1Fetch); - + _importListFetch.Movies.ForEach(m => m.ListId = 1); + GivenList(1, true); GivenCleanLevel("disabled"); - Subject.Execute(_command); + Subject.Execute(_commandAll); Mocker.GetMock() .Verify(v => v.AddMovies(It.Is>(s => s.Count == 5), true), Times.Once()); @@ -286,12 +313,16 @@ namespace NzbDrone.Core.Test.NetImport [Test] public void should_add_new_movies_from_multiple_list_to_library() { - GivenList(1, true, _netImport1Fetch); - GivenList(2, true, _netImport2Fetch); + _list2Movies.ForEach(m => m.ListId = 2); + _importListFetch.Movies.ForEach(m => m.ListId = 1); + _importListFetch.Movies.AddRange(_list2Movies); + + GivenList(1, true); + GivenList(2, true); GivenCleanLevel("disabled"); - Subject.Execute(_command); + Subject.Execute(_commandAll); Mocker.GetMock() .Verify(v => v.AddMovies(It.Is>(s => s.Count == 8), true), Times.Once()); @@ -300,12 +331,16 @@ namespace NzbDrone.Core.Test.NetImport [Test] public void should_add_new_movies_from_enabled_lists_to_library() { - GivenList(1, true, _netImport1Fetch); - GivenList(2, false, _netImport2Fetch); + _list2Movies.ForEach(m => m.ListId = 2); + _importListFetch.Movies.ForEach(m => m.ListId = 1); + _importListFetch.Movies.AddRange(_list2Movies); + + GivenList(1, true); + GivenList(2, false); GivenCleanLevel("disabled"); - Subject.Execute(_command); + Subject.Execute(_commandAll); Mocker.GetMock() .Verify(v => v.AddMovies(It.Is>(s => s.Count == 5), true), Times.Once()); @@ -314,14 +349,17 @@ namespace NzbDrone.Core.Test.NetImport [Test] public void should_not_add_duplicate_movies_from_seperate_lists() { - _netImport2Fetch.Movies[0].TmdbId = 4; + _list2Movies.ForEach(m => m.ListId = 2); + _importListFetch.Movies.ForEach(m => m.ListId = 1); + _importListFetch.Movies.AddRange(_list2Movies); + _importListFetch.Movies[0].TmdbId = 4; - GivenList(1, true, _netImport1Fetch); - GivenList(2, true, _netImport2Fetch); + GivenList(1, true); + GivenList(2, true); GivenCleanLevel("disabled"); - Subject.Execute(_command); + Subject.Execute(_commandAll); Mocker.GetMock() .Verify(v => v.AddMovies(It.Is>(s => s.Count == 7), true), Times.Once()); @@ -330,77 +368,45 @@ namespace NzbDrone.Core.Test.NetImport [Test] public void should_not_add_movie_from_on_exclusion_list() { - GivenList(1, true, _netImport1Fetch); - GivenList(2, true, _netImport2Fetch); + _list2Movies.ForEach(m => m.ListId = 2); + _importListFetch.Movies.ForEach(m => m.ListId = 1); + _importListFetch.Movies.AddRange(_list2Movies); + + GivenList(1, true); + GivenList(2, true); GivenCleanLevel("disabled"); Mocker.GetMock() - .Setup(v => v.IsMovieExcluded(_moviesList2[0].TmdbId)) - .Returns(true); + .Setup(v => v.GetAllExclusions()) + .Returns(new List { new ImportExclusion { TmdbId = _existingMovies[0].TmdbId } }); - Subject.Execute(_command); + Subject.Execute(_commandAll); Mocker.GetMock() - .Verify(v => v.AddMovies(It.Is>(s => s.Count == 7 && !s.Any(m => m.TmdbId == _moviesList2[0].TmdbId)), true), Times.Once()); + .Verify(v => v.AddMovies(It.Is>(s => s.Count == 7 && !s.Any(m => m.TmdbId == _existingMovies[0].TmdbId)), true), Times.Once()); } [Test] public void should_not_add_movie_that_exists_in_library() { - GivenList(1, true, _netImport1Fetch); - GivenList(2, true, _netImport2Fetch); + _list2Movies.ForEach(m => m.ListId = 2); + _importListFetch.Movies.ForEach(m => m.ListId = 1); + _importListFetch.Movies.AddRange(_list2Movies); + + GivenList(1, true); + GivenList(2, true); GivenCleanLevel("disabled"); Mocker.GetMock() - .Setup(v => v.MovieExists(_moviesList2[0])) - .Returns(true); + .Setup(v => v.AllMovieTmdbIds()) + .Returns(new List { _existingMovies[0].TmdbId }); - Subject.Execute(_command); + Subject.Execute(_commandAll); Mocker.GetMock() - .Verify(v => v.AddMovies(It.Is>(s => s.Count == 7 && !s.Any(m => m.TmdbId == _moviesList2[0].TmdbId)), true), Times.Once()); - } - - /* - [Test] - public void should_not_tmdb_map_movie_that_has_tmdbid_from_list() - { - GivenList(1, true, _netImport1Fetch); - GivenList(2, true, _netImport2Fetch); - - GivenCleanLevel("disabled"); - - Subject.Execute(_command); - - Mocker.GetMock() - .Verify(v => v.MapMovieToTmdbMovie(It.IsAny()), Times.Never()); - - Mocker.GetMock() - .Verify(v => v.AddMovies(It.Is>(s => s.Count == 8)), Times.Once()); + .Verify(v => v.AddMovies(It.Is>(s => s.Count == 7 && !s.Any(m => m.TmdbId == _existingMovies[0].TmdbId)), true), Times.Once()); } - - [Test] - public void should_tmdb_map_movie_that_has_no_tmdbid_from_list() - { - _netImport1Fetch.Movies[0].TmdbId = 0; - - GivenList(1, true, _netImport1Fetch); - - GivenCleanLevel("disabled"); - - Mocker.GetMock() - .Setup(v => v.MapMovieToTmdbMovie(It.IsAny())) - .Returns(Builder.CreateNew().Build()); - - Subject.Execute(_command); - - Mocker.GetMock() - .Verify(v => v.MapMovieToTmdbMovie(It.IsAny()), Times.Once()); - - Mocker.GetMock() - .Verify(v => v.AddMovies(It.Is>(s => s.Count == 5)), Times.Once()); - }*/ } } diff --git a/src/NzbDrone.Core.Test/NetImport/RSSImportFixture.cs b/src/NzbDrone.Core.Test/ImportListTests/RSSImportFixture.cs similarity index 92% rename from src/NzbDrone.Core.Test/NetImport/RSSImportFixture.cs rename to src/NzbDrone.Core.Test/ImportListTests/RSSImportFixture.cs index 286805f2f..4163f7c66 100644 --- a/src/NzbDrone.Core.Test/NetImport/RSSImportFixture.cs +++ b/src/NzbDrone.Core.Test/ImportListTests/RSSImportFixture.cs @@ -3,10 +3,10 @@ using FluentAssertions; using Moq; using NUnit.Framework; using NzbDrone.Common.Http; -using NzbDrone.Core.NetImport.RSSImport; +using NzbDrone.Core.ImportLists.RSSImport; using NzbDrone.Core.Test.Framework; -namespace NzbDrone.Core.Test.NetImport +namespace NzbDrone.Core.Test.ImportList { [TestFixture] public class RSSImportFixture : CoreTest diff --git a/src/NzbDrone.Core.Test/NetImport/RSSImportParserFixture.cs b/src/NzbDrone.Core.Test/ImportListTests/RSSImportParserFixture.cs similarity index 73% rename from src/NzbDrone.Core.Test/NetImport/RSSImportParserFixture.cs rename to src/NzbDrone.Core.Test/ImportListTests/RSSImportParserFixture.cs index face0effd..84019b7d7 100644 --- a/src/NzbDrone.Core.Test/NetImport/RSSImportParserFixture.cs +++ b/src/NzbDrone.Core.Test/ImportListTests/RSSImportParserFixture.cs @@ -3,20 +3,20 @@ using System.Text; using FluentAssertions; using NUnit.Framework; using NzbDrone.Common.Http; -using NzbDrone.Core.NetImport; -using NzbDrone.Core.NetImport.RSSImport; +using NzbDrone.Core.ImportLists; +using NzbDrone.Core.ImportLists.RSSImport; using NzbDrone.Core.Test.Framework; -namespace NzbDrone.Core.Test.NetImport +namespace NzbDrone.Core.Test.ImportList { public class RSSImportTest : CoreTest { - private NetImportResponse CreateResponse(string url, string content) + private ImportListResponse CreateResponse(string url, string content) { var httpRequest = new HttpRequest(url); var httpResponse = new HttpResponse(httpRequest, new HttpHeader(), Encoding.UTF8.GetBytes(content)); - return new NetImportResponse(new NetImportRequest(httpRequest), httpResponse); + return new ImportListResponse(new ImportListRequest(httpRequest), httpResponse); } [Test] diff --git a/src/NzbDrone.Core.Test/Messaging/Commands/CommandQueueFixture.cs b/src/NzbDrone.Core.Test/Messaging/Commands/CommandQueueFixture.cs new file mode 100644 index 000000000..5589eb414 --- /dev/null +++ b/src/NzbDrone.Core.Test/Messaging/Commands/CommandQueueFixture.cs @@ -0,0 +1,191 @@ +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Download; +using NzbDrone.Core.ImportLists; +using NzbDrone.Core.Messaging.Commands; +using NzbDrone.Core.Movies.Commands; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Update.Commands; + +namespace NzbDrone.Core.Test.Messaging.Commands +{ + [TestFixture] + public class CommandQueueFixture : CoreTest + { + private void GivenStartedDiskCommand() + { + var commandModel = Builder + .CreateNew() + .With(c => c.Name = "ProcessMonitoredDownloads") + .With(c => c.Body = new ProcessMonitoredDownloadsCommand()) + .With(c => c.Status = CommandStatus.Started) + .Build(); + + Subject.Add(commandModel); + } + + private void GivenStartedTypeExclusiveCommand() + { + var commandModel = Builder + .CreateNew() + .With(c => c.Name = "ImportListSync") + .With(c => c.Body = new ImportListSyncCommand()) + .With(c => c.Status = CommandStatus.Started) + .Build(); + + Subject.Add(commandModel); + } + + private void GivenStartedExclusiveCommand() + { + var commandModel = Builder + .CreateNew() + .With(c => c.Name = "ApplicationUpdate") + .With(c => c.Body = new ApplicationUpdateCommand()) + .With(c => c.Status = CommandStatus.Started) + .Build(); + + Subject.Add(commandModel); + } + + [Test] + public void should_not_return_disk_access_command_if_another_running() + { + GivenStartedDiskCommand(); + + var newCommandModel = Builder + .CreateNew() + .With(c => c.Name = "ProcessMonitoredDownloads") + .With(c => c.Body = new ProcessMonitoredDownloadsCommand()) + .Build(); + + Subject.Add(newCommandModel); + + Subject.TryGet(out var command); + + command.Should().BeNull(); + } + + [Test] + public void should_not_return_type_exclusive_command_if_another_and_disk_access_command_running() + { + GivenStartedTypeExclusiveCommand(); + GivenStartedDiskCommand(); + + var newCommandModel = Builder + .CreateNew() + .With(c => c.Name = "ImportListSync") + .With(c => c.Body = new ImportListSyncCommand()) + .Build(); + + Subject.Add(newCommandModel); + + Subject.TryGet(out var command); + + command.Should().BeNull(); + } + + [Test] + public void should_not_return_type_exclusive_command_if_another_running() + { + GivenStartedTypeExclusiveCommand(); + + var newCommandModel = Builder + .CreateNew() + .With(c => c.Name = "ImportListSync") + .With(c => c.Body = new ImportListSyncCommand()) + .Build(); + + Subject.Add(newCommandModel); + + Subject.TryGet(out var command); + + command.Should().BeNull(); + } + + [Test] + public void should_return_type_exclusive_command_if_another_not_running() + { + GivenStartedDiskCommand(); + + var newCommandModel = Builder + .CreateNew() + .With(c => c.Name = "ImportListSync") + .With(c => c.Body = new ImportListSyncCommand()) + .Build(); + + Subject.Add(newCommandModel); + + Subject.TryGet(out var command); + + command.Should().NotBeNull(); + command.Status.Should().Be(CommandStatus.Started); + } + + [Test] + public void should_return_regular_command_if_type_exclusive_command_running() + { + GivenStartedTypeExclusiveCommand(); + + var newCommandModel = Builder + .CreateNew() + .With(c => c.Name = "RefreshMovie") + .With(c => c.Body = new RefreshMovieCommand()) + .Build(); + + Subject.Add(newCommandModel); + + Subject.TryGet(out var command); + + command.Should().NotBeNull(); + command.Status.Should().Be(CommandStatus.Started); + } + + [Test] + public void should_not_return_exclusive_command_if_any_running() + { + GivenStartedDiskCommand(); + + var newCommandModel = Builder + .CreateNew() + .With(c => c.Name = "ApplicationUpdate") + .With(c => c.Body = new ApplicationUpdateCommand()) + .Build(); + + Subject.Add(newCommandModel); + + Subject.TryGet(out var command); + + command.Should().BeNull(); + } + + [Test] + public void should_not_return_any_command_if_exclusive_running() + { + GivenStartedExclusiveCommand(); + + var newCommandModel = Builder + .CreateNew() + .With(c => c.Name = "RefreshMovie") + .With(c => c.Body = new RefreshMovieCommand()) + .Build(); + + Subject.Add(newCommandModel); + + Subject.TryGet(out var command); + + command.Should().BeNull(); + } + + [Test] + public void should_return_null_if_nothing_queued() + { + GivenStartedDiskCommand(); + + Subject.TryGet(out var command); + + command.Should().BeNull(); + } + } +} diff --git a/src/NzbDrone.Core.Test/Profiles/ProfileServiceFixture.cs b/src/NzbDrone.Core.Test/Profiles/ProfileServiceFixture.cs index 5745949c8..b4739718b 100644 --- a/src/NzbDrone.Core.Test/Profiles/ProfileServiceFixture.cs +++ b/src/NzbDrone.Core.Test/Profiles/ProfileServiceFixture.cs @@ -5,10 +5,10 @@ using FluentAssertions; using Moq; using NUnit.Framework; using NzbDrone.Core.CustomFormats; +using NzbDrone.Core.ImportLists; using NzbDrone.Core.Languages; using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Movies; -using NzbDrone.Core.NetImport; using NzbDrone.Core.Profiles; using NzbDrone.Core.Test.CustomFormats; using NzbDrone.Core.Test.Framework; @@ -56,13 +56,13 @@ namespace NzbDrone.Core.Test.Profiles .With(c => c.ProfileId = 2) .Build().ToList(); - var netImportList = Builder.CreateListOfSize(3) + var importList = Builder.CreateListOfSize(3) .All() .With(c => c.ProfileId = 1) .Build().ToList(); Mocker.GetMock().Setup(c => c.GetAllMovies()).Returns(movieList); - Mocker.GetMock().Setup(c => c.All()).Returns(netImportList); + Mocker.GetMock().Setup(c => c.All()).Returns(importList); Assert.Throws(() => Subject.Delete(2)); @@ -77,13 +77,13 @@ namespace NzbDrone.Core.Test.Profiles .With(c => c.ProfileId = 1) .Build().ToList(); - var netImportList = Builder.CreateListOfSize(3) + var importList = Builder.CreateListOfSize(3) .Random(1) .With(c => c.ProfileId = 2) .Build().ToList(); Mocker.GetMock().Setup(c => c.GetAllMovies()).Returns(movieList); - Mocker.GetMock().Setup(c => c.All()).Returns(netImportList); + Mocker.GetMock().Setup(c => c.All()).Returns(importList); Assert.Throws(() => Subject.Delete(2)); @@ -98,13 +98,13 @@ namespace NzbDrone.Core.Test.Profiles .With(c => c.ProfileId = 2) .Build().ToList(); - var netImportList = Builder.CreateListOfSize(3) + var importList = Builder.CreateListOfSize(3) .All() .With(c => c.ProfileId = 2) .Build().ToList(); Mocker.GetMock().Setup(c => c.GetAllMovies()).Returns(movieList); - Mocker.GetMock().Setup(c => c.All()).Returns(netImportList); + Mocker.GetMock().Setup(c => c.All()).Returns(importList); Subject.Delete(1); diff --git a/src/NzbDrone.Core.Test/ThingiProvider/ProviderBaseFixture.cs b/src/NzbDrone.Core.Test/ThingiProvider/ProviderBaseFixture.cs deleted file mode 100644 index 6107479e4..000000000 --- a/src/NzbDrone.Core.Test/ThingiProvider/ProviderBaseFixture.cs +++ /dev/null @@ -1,29 +0,0 @@ -using FizzWare.NBuilder; -using FluentAssertions; -using NUnit.Framework; -using NzbDrone.Core.Indexers; -using NzbDrone.Core.Indexers.Newznab; -using NzbDrone.Core.Test.Framework; - -namespace NzbDrone.Core.Test.ThingiProvider -{ - public class ProviderRepositoryFixture : DbTest - { - [Test] - public void should_read_write_download_provider() - { - var model = Builder.CreateNew().BuildNew(); - var newznabSettings = Builder.CreateNew().Build(); - model.Settings = newznabSettings; - Subject.Insert(model); - - var storedProvider = Subject.Single(); - - storedProvider.Settings.Should().BeOfType(); - - var storedSetting = (NewznabSettings)storedProvider.Settings; - - storedSetting.Should().BeEquivalentTo(newznabSettings, o => o.IncludingAllRuntimeProperties()); - } - } -} diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index 2c56563cb..122c43544 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -116,11 +116,11 @@ namespace NzbDrone.Core.Configuration set { SetValue("AvailabilityDelay", value); } } - public int NetImportSyncInterval + public int ImportListSyncInterval { - get { return GetValueInt("NetImportSyncInterval", 60); } + get { return GetValueInt("ImportListSyncInterval", 240); } - set { SetValue("NetImportSyncInterval", value); } + set { SetValue("ImportListSyncInterval", value); } } public string ListSyncLevel diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index 16edabd22..ed38e7a50 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -58,7 +58,7 @@ namespace NzbDrone.Core.Configuration bool AllowHardcodedSubs { get; set; } string WhitelistedHardcodedSubs { get; set; } - int NetImportSyncInterval { get; set; } + int ImportListSyncInterval { get; set; } string ListSyncLevel { get; set; } string ImportExclusions { get; set; } diff --git a/src/NzbDrone.Core/Datastore/Migration/181_list_movies_table.cs b/src/NzbDrone.Core/Datastore/Migration/181_list_movies_table.cs new file mode 100644 index 000000000..dbea69bb7 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/181_list_movies_table.cs @@ -0,0 +1,44 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(181)] + public class list_movies_table : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Rename.Table("NetImport").To("ImportLists"); + Rename.Table("NetImportStatus").To("ImportListStatus"); + + Execute.Sql("UPDATE Config SET Key = 'importlistsyncinterval' WHERE Key = 'netimportsyncinterval'"); + + Alter.Table("ImportLists").AddColumn("SearchOnAdd").AsBoolean().WithDefaultValue(false); + + Create.TableForModel("ImportListMovies") + .WithColumn("ImdbId").AsString().Nullable() + .WithColumn("TmdbId").AsInt32() + .WithColumn("ListId").AsInt32() + .WithColumn("Title").AsString() + .WithColumn("SortTitle").AsString().Nullable() + .WithColumn("Status").AsInt32() + .WithColumn("Overview").AsString().Nullable() + .WithColumn("Images").AsString() + .WithColumn("LastInfoSync").AsDateTime().Nullable() + .WithColumn("Runtime").AsInt32() + .WithColumn("InCinemas").AsDateTime().Nullable() + .WithColumn("Year").AsInt32().Nullable() + .WithColumn("Ratings").AsString().Nullable() + .WithColumn("Genres").AsString().Nullable() + .WithColumn("Certification").AsString().Nullable() + .WithColumn("Collection").AsString().Nullable() + .WithColumn("Website").AsString().Nullable() + .WithColumn("OriginalTitle").AsString().Nullable() + .WithColumn("PhysicalRelease").AsDateTime().Nullable() + .WithColumn("Translations").AsString() + .WithColumn("Studio").AsString().Nullable() + .WithColumn("YouTubeTrailerId").AsString().Nullable() + .WithColumn("DigitalRelease").AsDateTime().Nullable(); + } + } +} diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index 710de37bd..0163362d4 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -17,6 +17,9 @@ using NzbDrone.Core.Extras.Metadata.Files; using NzbDrone.Core.Extras.Others; using NzbDrone.Core.Extras.Subtitles; using NzbDrone.Core.History; +using NzbDrone.Core.ImportLists; +using NzbDrone.Core.ImportLists.ImportExclusions; +using NzbDrone.Core.ImportLists.ImportListMovies; using NzbDrone.Core.Indexers; using NzbDrone.Core.Instrumentation; using NzbDrone.Core.Jobs; @@ -27,8 +30,6 @@ using NzbDrone.Core.Movies; using NzbDrone.Core.Movies.AlternativeTitles; using NzbDrone.Core.Movies.Credits; using NzbDrone.Core.Movies.Translations; -using NzbDrone.Core.NetImport; -using NzbDrone.Core.NetImport.ImportExclusions; using NzbDrone.Core.Notifications; using NzbDrone.Core.Organizer; using NzbDrone.Core.Parser.Model; @@ -74,7 +75,7 @@ namespace NzbDrone.Core.Datastore .Ignore(i => i.SupportsSearch) .Ignore(d => d.Tags); - Mapper.Entity("NetImport").RegisterModel() + Mapper.Entity("ImportLists").RegisterModel() .Ignore(x => x.ImplementationName) .Ignore(i => i.ListType) .Ignore(i => i.Enable); @@ -102,7 +103,10 @@ namespace NzbDrone.Core.Datastore .Ignore(f => f.Path); Mapper.Entity("Movies").RegisterModel() - .Ignore(s => s.RootFolderPath); + .Ignore(s => s.RootFolderPath) + .Ignore(s => s.Translations); + + Mapper.Entity("ImportListMovies").RegisterModel(); Mapper.Entity("AlternativeTitles").RegisterModel(); @@ -140,7 +144,7 @@ namespace NzbDrone.Core.Datastore Mapper.Entity("IndexerStatus").RegisterModel(); Mapper.Entity("DownloadClientStatus").RegisterModel(); - Mapper.Entity("NetImportStatus").RegisterModel(); + Mapper.Entity("ImportListStatus").RegisterModel(); Mapper.Entity("CustomFilters").RegisterModel(); @@ -169,6 +173,7 @@ namespace NzbDrone.Core.Datastore SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter(new QualityIntConverter(), new LanguageIntConverter())); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter()); + SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>()); SqlMapper.AddTypeHandler(new OsPathConverter()); SqlMapper.RemoveTypeMap(typeof(Guid)); diff --git a/src/NzbDrone.Core/HealthCheck/Checks/NetImportStatusCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/ImportListStatusCheck.cs similarity index 57% rename from src/NzbDrone.Core/HealthCheck/Checks/NetImportStatusCheck.cs rename to src/NzbDrone.Core/HealthCheck/Checks/ImportListStatusCheck.cs index beccb3487..61e56c17c 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/NetImportStatusCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/ImportListStatusCheck.cs @@ -1,20 +1,20 @@ using System.Linq; using NzbDrone.Common.Extensions; +using NzbDrone.Core.ImportLists; using NzbDrone.Core.Localization; -using NzbDrone.Core.NetImport; using NzbDrone.Core.ThingiProvider.Events; namespace NzbDrone.Core.HealthCheck.Checks { - [CheckOn(typeof(ProviderUpdatedEvent))] - [CheckOn(typeof(ProviderDeletedEvent))] - [CheckOn(typeof(ProviderStatusChangedEvent))] - public class NetImportStatusCheck : HealthCheckBase + [CheckOn(typeof(ProviderUpdatedEvent))] + [CheckOn(typeof(ProviderDeletedEvent))] + [CheckOn(typeof(ProviderStatusChangedEvent))] + public class ImportListStatusCheck : HealthCheckBase { - private readonly INetImportFactory _providerFactory; - private readonly INetImportStatusService _providerStatusService; + private readonly IImportListFactory _providerFactory; + private readonly IImportListStatusService _providerStatusService; - public NetImportStatusCheck(INetImportFactory providerFactory, INetImportStatusService providerStatusService, ILocalizationService localizationService) + public ImportListStatusCheck(IImportListFactory providerFactory, IImportListStatusService providerStatusService, ILocalizationService localizationService) : base(localizationService) { _providerFactory = providerFactory; @@ -37,10 +37,10 @@ namespace NzbDrone.Core.HealthCheck.Checks if (backOffProviders.Count == enabledProviders.Count) { - return new HealthCheck(GetType(), HealthCheckResult.Error, _localizationService.GetLocalizedString("NetImportStatusCheckAllClientMessage"), "#lists-are-unavailable-due-to-failures"); + return new HealthCheck(GetType(), HealthCheckResult.Error, _localizationService.GetLocalizedString("ImportListStatusCheckAllClientMessage"), "#lists-are-unavailable-due-to-failures"); } - return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format(_localizationService.GetLocalizedString("NetImportStatusCheckSingleClientMessage"), string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name))), "#lists-are-unavailable-due-to-failures"); + return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format(_localizationService.GetLocalizedString("ImportListStatusCheckSingleClientMessage"), string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name))), "#lists-are-unavailable-due-to-failures"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs index b12ea8563..caab4d5d3 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs @@ -19,7 +19,7 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers { using (var mapper = _database.OpenConnection()) { - var usedTags = new[] { "Movies", "Notifications", "DelayProfiles", "Restrictions", "NetImport" } + var usedTags = new[] { "Movies", "Notifications", "DelayProfiles", "Restrictions", "ImportLists" } .SelectMany(v => GetUsedTags(v, mapper)) .Distinct() .ToArray(); diff --git a/src/NzbDrone.Core/NetImport/NetImportListLevels.cs b/src/NzbDrone.Core/ImportLists/CleanLibraryLevel.cs similarity index 60% rename from src/NzbDrone.Core/NetImport/NetImportListLevels.cs rename to src/NzbDrone.Core/ImportLists/CleanLibraryLevel.cs index 3d8587da4..4869b2673 100644 --- a/src/NzbDrone.Core/NetImport/NetImportListLevels.cs +++ b/src/NzbDrone.Core/ImportLists/CleanLibraryLevel.cs @@ -1,6 +1,6 @@ -namespace NzbDrone.Core.NetImport +namespace NzbDrone.Core.ImportLists { - public enum NetImportCleanLibraryLevels + public enum CleanLibraryLevel { Disabled, LogOnly, diff --git a/src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoAPI.cs b/src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoAPI.cs similarity index 98% rename from src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoAPI.cs rename to src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoAPI.cs index 45ec3eed6..cd59a17fc 100644 --- a/src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoAPI.cs +++ b/src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoAPI.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace NzbDrone.Core.NetImport.CouchPotato +namespace NzbDrone.Core.ImportLists.CouchPotato { public class CouchPotatoResponse { diff --git a/src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoImport.cs b/src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoImport.cs new file mode 100644 index 000000000..37f5d28b2 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoImport.cs @@ -0,0 +1,31 @@ +using NLog; +using NzbDrone.Common.Http; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Parser; + +namespace NzbDrone.Core.ImportLists.CouchPotato +{ + public class CouchPotatoImport : HttpImportListBase + { + public override string Name => "CouchPotato"; + + public override ImportListType ListType => ImportListType.Program; + public override bool Enabled => true; + public override bool EnableAuto => false; + + public CouchPotatoImport(IHttpClient httpClient, IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, Logger logger) + : base(httpClient, importListStatusService, configService, parsingService, logger) + { + } + + public override IImportListRequestGenerator GetRequestGenerator() + { + return new CouchPotatoRequestGenerator() { Settings = Settings }; + } + + public override IParseImportListResponse GetParser() + { + return new CouchPotatoParser(); + } + } +} diff --git a/src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoParser.cs b/src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoParser.cs similarity index 53% rename from src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoParser.cs rename to src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoParser.cs index 2a1784cb0..f6d805c53 100644 --- a/src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoParser.cs +++ b/src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoParser.cs @@ -1,34 +1,33 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Net; using Newtonsoft.Json; using NzbDrone.Common.Extensions; -using NzbDrone.Core.NetImport.Exceptions; +using NzbDrone.Core.ImportLists.Exceptions; +using NzbDrone.Core.ImportLists.ImportListMovies; -namespace NzbDrone.Core.NetImport.CouchPotato +namespace NzbDrone.Core.ImportLists.CouchPotato { - public class CouchPotatoParser : IParseNetImportResponse + public class CouchPotatoParser : IParseImportListResponse { - private readonly CouchPotatoSettings _settings; - private NetImportResponse _importResponse; + private ImportListResponse _importListResponse; - public CouchPotatoParser(CouchPotatoSettings settings) + public CouchPotatoParser() { - _settings = settings; } - public IList ParseResponse(NetImportResponse importResponse) + public IList ParseResponse(ImportListResponse importListResponse) { - _importResponse = importResponse; + _importListResponse = importListResponse; - var movies = new List(); + var movies = new List(); - if (!PreProcess(_importResponse)) + if (!PreProcess(_importListResponse)) { return movies; } - var jsonResponse = JsonConvert.DeserializeObject(_importResponse.Content); + var jsonResponse = JsonConvert.DeserializeObject(_importListResponse.Content); // no movies were return if (jsonResponse.total == 0) @@ -48,7 +47,7 @@ namespace NzbDrone.Core.NetImport.CouchPotato // if there are no releases at all the movie wasn't found on CP, so return movies if (!item.releases.Any() && item.type == "movie") { - movies.AddIfNotNull(new Movies.Movie() + movies.AddIfNotNull(new ImportListMovie() { Title = item.title, ImdbId = item.info.imdb, @@ -62,12 +61,11 @@ namespace NzbDrone.Core.NetImport.CouchPotato bool isCompleted = item.releases.Any(rel => (rel.status == "done" || rel.status == "seeding")); if (!isCompleted) { - movies.AddIfNotNull(new Movies.Movie() + movies.AddIfNotNull(new ImportListMovie() { Title = item.title, ImdbId = item.info.imdb, - TmdbId = tmdbid, - Monitored = false + TmdbId = tmdbid }); } } @@ -77,17 +75,17 @@ namespace NzbDrone.Core.NetImport.CouchPotato return movies; } - protected virtual bool PreProcess(NetImportResponse netImportResponse) + protected virtual bool PreProcess(ImportListResponse importListResponse) { - if (netImportResponse.HttpResponse.StatusCode != HttpStatusCode.OK) + if (importListResponse.HttpResponse.StatusCode != HttpStatusCode.OK) { - throw new NetImportException(netImportResponse, "List API call resulted in an unexpected StatusCode [{0}]", netImportResponse.HttpResponse.StatusCode); + throw new ImportListException(importListResponse, "List API call resulted in an unexpected StatusCode [{0}]", importListResponse.HttpResponse.StatusCode); } - if (netImportResponse.HttpResponse.Headers.ContentType != null && netImportResponse.HttpResponse.Headers.ContentType.Contains("text/json") && - netImportResponse.HttpRequest.Headers.Accept != null && !netImportResponse.HttpRequest.Headers.Accept.Contains("text/json")) + if (importListResponse.HttpResponse.Headers.ContentType != null && importListResponse.HttpResponse.Headers.ContentType.Contains("text/json") && + importListResponse.HttpRequest.Headers.Accept != null && !importListResponse.HttpRequest.Headers.Accept.Contains("text/json")) { - throw new NetImportException(netImportResponse, "List responded with html content. Site is likely blocked or unavailable."); + throw new ImportListException(importListResponse, "List responded with html content. Site is likely blocked or unavailable."); } return true; diff --git a/src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoRequestGenerator.cs b/src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoRequestGenerator.cs similarity index 57% rename from src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoRequestGenerator.cs rename to src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoRequestGenerator.cs index 10146a821..5abd911db 100644 --- a/src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoRequestGenerator.cs +++ b/src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoRequestGenerator.cs @@ -1,22 +1,22 @@ using System.Collections.Generic; using NzbDrone.Common.Http; -namespace NzbDrone.Core.NetImport.CouchPotato +namespace NzbDrone.Core.ImportLists.CouchPotato { - public class CouchPotatoRequestGenerator : INetImportRequestGenerator + public class CouchPotatoRequestGenerator : IImportListRequestGenerator { public CouchPotatoSettings Settings { get; set; } - public virtual NetImportPageableRequestChain GetMovies() + public virtual ImportListPageableRequestChain GetMovies() { - var pageableRequests = new NetImportPageableRequestChain(); + var pageableRequests = new ImportListPageableRequestChain(); pageableRequests.Add(GetMovies(null)); return pageableRequests; } - private IEnumerable GetMovies(string searchParameters) + private IEnumerable GetMovies(string searchParameters) { var urlBase = ""; if (!string.IsNullOrWhiteSpace(Settings.UrlBase)) @@ -31,7 +31,7 @@ namespace NzbDrone.Core.NetImport.CouchPotato status = "?status=active"; } - var request = new NetImportRequest($"{Settings.Link.Trim()}:{Settings.Port}{urlBase}/api/{Settings.ApiKey}/movie.list/{status}", HttpAccept.Json); + var request = new ImportListRequest($"{Settings.Link.Trim()}:{Settings.Port}{urlBase}/api/{Settings.ApiKey}/movie.list/{status}", HttpAccept.Json); yield return request; } } diff --git a/src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoSettings.cs b/src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoSettings.cs similarity index 97% rename from src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoSettings.cs rename to src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoSettings.cs index aa04cc178..1ac64def2 100644 --- a/src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoSettings.cs +++ b/src/NzbDrone.Core/ImportLists/CouchPotato/CouchPotatoSettings.cs @@ -3,7 +3,7 @@ using NzbDrone.Core.Annotations; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; -namespace NzbDrone.Core.NetImport.CouchPotato +namespace NzbDrone.Core.ImportLists.CouchPotato { public class CouchPotatoSettingsValidator : AbstractValidator { diff --git a/src/NzbDrone.Core/ImportLists/Exceptions/ImportListException.cs b/src/NzbDrone.Core/ImportLists/Exceptions/ImportListException.cs new file mode 100644 index 000000000..1f18ecc15 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/Exceptions/ImportListException.cs @@ -0,0 +1,21 @@ +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Core.ImportLists.Exceptions +{ + public class ImportListException : NzbDroneException + { + public ImportListException(ImportListResponse response, string message, params object[] args) + : base(message, args) + { + Response = response; + } + + public ImportListException(ImportListResponse response, string message) + : base(message) + { + Response = response; + } + + public ImportListResponse Response { get; private set; } + } +} diff --git a/src/NzbDrone.Core/ImportLists/FetchAndParseImportListService.cs b/src/NzbDrone.Core/ImportLists/FetchAndParseImportListService.cs new file mode 100644 index 000000000..52cb02cb2 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/FetchAndParseImportListService.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Instrumentation.Extensions; +using NzbDrone.Common.TPL; +using NzbDrone.Core.ImportLists.ImportListMovies; +using NzbDrone.Core.MetadataSource; +using NzbDrone.Core.Movies; + +namespace NzbDrone.Core.ImportLists +{ + public interface IFetchAndParseImportList + { + ImportListFetchResult Fetch(); + ImportListFetchResult FetchSingleList(ImportListDefinition definition); + } + + public class FetchAndParseImportListService : IFetchAndParseImportList + { + private readonly IImportListFactory _importListFactory; + private readonly IImportListStatusService _importListStatusService; + private readonly IImportListMovieService _listMovieService; + private readonly ISearchForNewMovie _movieSearch; + private readonly Logger _logger; + + public FetchAndParseImportListService(IImportListFactory importListFactory, + IImportListStatusService importListStatusService, + IImportListMovieService listMovieService, + ISearchForNewMovie movieSearch, + Logger logger) + { + _importListFactory = importListFactory; + _importListStatusService = importListStatusService; + _listMovieService = listMovieService; + _movieSearch = movieSearch; + _logger = logger; + } + + public ImportListFetchResult Fetch() + { + var result = new ImportListFetchResult(); + + var importLists = _importListFactory.Enabled(); + + if (!importLists.Any()) + { + _logger.Debug("No available import lists. check your configuration."); + return result; + } + + _logger.Debug("Available import lists {0}", importLists.Count); + + var taskList = new List(); + var taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None); + + foreach (var importList in importLists) + { + _logger.ProgressInfo("Syncing Movies for List: {0}", importList.Name); + + var importListLocal = importList; + var blockedLists = _importListStatusService.GetBlockedProviders().ToDictionary(v => v.ProviderId, v => v); + + if (blockedLists.TryGetValue(importList.Definition.Id, out ImportListStatus blockedListStatus)) + { + _logger.Debug("Temporarily ignoring list {0} till {1} due to recent failures.", importList.Definition.Name, blockedListStatus.DisabledTill.Value.ToLocalTime()); + result.AnyFailure |= true; //Ensure we don't clean if a list is down + continue; + } + + var task = taskFactory.StartNew(() => + { + try + { + var importListReports = importListLocal.Fetch(); + + lock (result) + { + _logger.Debug("Found {0} from {1}", importListReports.Movies.Count, importList.Name); + + if (!importListReports.AnyFailure) + { + // TODO some opportunity to bulk map here if we had the tmdbIds + var listMovies = importListReports.Movies.Select(x => + { + // Is it existing in result + var movie = result.Movies.FirstOrDefault(r => r.TmdbId == x.TmdbId); + + if (movie != null) + { + movie.ListId = importList.Definition.Id; + } + + return movie ?? MapMovieReport(x); + }).Where(x => x.TmdbId > 0).ToList(); + + listMovies = listMovies.DistinctBy(x => x.TmdbId).ToList(); + listMovies.ForEach(m => m.ListId = importList.Definition.Id); + + result.Movies.AddRange(listMovies); + _listMovieService.SyncMoviesForList(listMovies, importList.Definition.Id); + } + + result.AnyFailure |= importListReports.AnyFailure; + } + } + catch (Exception e) + { + _logger.Error(e, "Error during Import List Sync for list {0}", importList.Name); + } + }).LogExceptions(); + + taskList.Add(task); + } + + Task.WaitAll(taskList.ToArray()); + + _logger.Debug("Found {0} reports for all lists", result.Movies.Count); + + return result; + } + + public ImportListFetchResult FetchSingleList(ImportListDefinition definition) + { + var result = new ImportListFetchResult(); + + var importList = _importListFactory.GetInstance(definition); + + if (importList == null || !definition.Enable) + { + _logger.Debug("Import list {0} is not enabled. No Movies will be added"); + return result; + } + + var importListLocal = importList; + + try + { + var importListReports = importListLocal.Fetch(); + + lock (result) + { + _logger.Debug("Found {0} from {1}", importListReports.Movies.Count, importList.Name); + + if (!importListReports.AnyFailure) + { + // TODO some opportunity to bulk map here if we had the tmdbIds + var listMovies = importListReports.Movies.Select(x => + { + return MapMovieReport(x); + }).Where(x => x.TmdbId > 0).ToList(); + + listMovies = listMovies.DistinctBy(x => x.TmdbId).ToList(); + + result.Movies.AddRange(listMovies); + _listMovieService.SyncMoviesForList(listMovies, importList.Definition.Id); + } + + result.AnyFailure |= importListReports.AnyFailure; + } + } + catch (Exception e) + { + _logger.Error(e, "Error during Import List Sync for list {0}", importList.Name); + } + + _logger.Debug("Found {0} reports for list {1}", result.Movies.Count, importList.Name); + + return result; + } + + private ImportListMovie MapMovieReport(ImportListMovie report) + { + var mappedMovie = _movieSearch.MapMovieToTmdbMovie(new Movie { Title = report.Title, TmdbId = report.TmdbId, ImdbId = report.ImdbId, Year = report.Year }); + + var mappedListMovie = new ImportListMovie { ListId = report.ListId }; + + if (mappedMovie != null) + { + mappedListMovie.TmdbId = mappedMovie.TmdbId; + mappedListMovie.ImdbId = mappedMovie.ImdbId; + mappedListMovie.Title = mappedMovie.Title; + mappedListMovie.SortTitle = mappedMovie?.SortTitle; + mappedListMovie.Year = mappedMovie.Year; + mappedListMovie.Overview = mappedMovie.Overview; + mappedListMovie.Ratings = mappedMovie.Ratings; + mappedListMovie.Studio = mappedMovie.Studio; + mappedListMovie.Certification = mappedMovie.Certification; + mappedListMovie.Collection = mappedMovie.Collection; + mappedListMovie.Status = mappedMovie.Status; + mappedListMovie.Images = mappedMovie.Images; + mappedListMovie.Website = mappedMovie.Website; + mappedListMovie.YouTubeTrailerId = mappedMovie.YouTubeTrailerId; + mappedListMovie.Translations = mappedMovie.Translations; + mappedListMovie.InCinemas = mappedMovie.InCinemas; + mappedListMovie.PhysicalRelease = mappedMovie.PhysicalRelease; + mappedListMovie.DigitalRelease = mappedMovie.DigitalRelease; + mappedListMovie.Genres = mappedMovie.Genres; + mappedListMovie.Runtime = mappedMovie.Runtime; + } + + return mappedListMovie; + } + } +} diff --git a/src/NzbDrone.Core/NetImport/HttpNetImportBase.cs b/src/NzbDrone.Core/ImportLists/HttpImportListBase.cs similarity index 66% rename from src/NzbDrone.Core/NetImport/HttpNetImportBase.cs rename to src/NzbDrone.Core/ImportLists/HttpImportListBase.cs index fa300e5f2..e5421356a 100644 --- a/src/NzbDrone.Core/NetImport/HttpNetImportBase.cs +++ b/src/NzbDrone.Core/ImportLists/HttpImportListBase.cs @@ -8,15 +8,15 @@ using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; using NzbDrone.Core.Http.CloudFlare; +using NzbDrone.Core.ImportLists.Exceptions; +using NzbDrone.Core.ImportLists.ImportListMovies; using NzbDrone.Core.Indexers.Exceptions; -using NzbDrone.Core.Movies; -using NzbDrone.Core.NetImport.Exceptions; using NzbDrone.Core.Parser; using NzbDrone.Core.ThingiProvider; -namespace NzbDrone.Core.NetImport +namespace NzbDrone.Core.ImportLists { - public abstract class HttpNetImportBase : NetImportBase + public abstract class HttpImportListBase : ImportListBase where TSettings : IProviderConfig, new() { protected readonly IHttpClient _httpClient; @@ -27,24 +27,24 @@ namespace NzbDrone.Core.NetImport public virtual int PageSize => 20; public virtual TimeSpan RateLimit => TimeSpan.FromSeconds(2); - public abstract INetImportRequestGenerator GetRequestGenerator(); - public abstract IParseNetImportResponse GetParser(); + public abstract IImportListRequestGenerator GetRequestGenerator(); + public abstract IParseImportListResponse GetParser(); - protected HttpNetImportBase(IHttpClient httpClient, INetImportStatusService netImportStatusService, IConfigService configService, IParsingService parsingService, Logger logger) - : base(netImportStatusService, configService, parsingService, logger) + protected HttpImportListBase(IHttpClient httpClient, IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, Logger logger) + : base(importListStatusService, configService, parsingService, logger) { _httpClient = httpClient; } - public override NetImportFetchResult Fetch() + public override ImportListFetchResult Fetch() { var generator = GetRequestGenerator(); return FetchMovies(generator.GetMovies()); } - protected virtual NetImportFetchResult FetchMovies(NetImportPageableRequestChain pageableRequestChain, bool isRecent = false) + protected virtual ImportListFetchResult FetchMovies(ImportListPageableRequestChain pageableRequestChain, bool isRecent = false) { - var movies = new List(); + var movies = new List(); var url = string.Empty; var parser = GetParser(); @@ -58,7 +58,7 @@ namespace NzbDrone.Core.NetImport var pageableRequests = pageableRequestChain.GetTier(i); foreach (var pageableRequest in pageableRequests) { - var pagedReleases = new List(); + var pagedReleases = new List(); foreach (var request in pageableRequest) { url = request.Url.FullUri; @@ -75,7 +75,7 @@ namespace NzbDrone.Core.NetImport } } - _netImportStatusService.RecordSuccess(Definition.Id); + _importListStatusService.RecordSuccess(Definition.Id); anyFailure = false; } catch (WebException webException) @@ -83,11 +83,11 @@ namespace NzbDrone.Core.NetImport if (webException.Status == WebExceptionStatus.NameResolutionFailure || webException.Status == WebExceptionStatus.ConnectFailure) { - _netImportStatusService.RecordConnectionFailure(Definition.Id); + _importListStatusService.RecordConnectionFailure(Definition.Id); } else { - _netImportStatusService.RecordFailure(Definition.Id); + _importListStatusService.RecordFailure(Definition.Id); } if (webException.Message.Contains("502") || webException.Message.Contains("503") || @@ -104,28 +104,28 @@ namespace NzbDrone.Core.NetImport { if (ex.RetryAfter != TimeSpan.Zero) { - _netImportStatusService.RecordFailure(Definition.Id, ex.RetryAfter); + _importListStatusService.RecordFailure(Definition.Id, ex.RetryAfter); } else { - _netImportStatusService.RecordFailure(Definition.Id, TimeSpan.FromHours(1)); + _importListStatusService.RecordFailure(Definition.Id, TimeSpan.FromHours(1)); } _logger.Warn("API Request Limit reached for {0}", this); } catch (HttpException ex) { - _netImportStatusService.RecordFailure(Definition.Id); + _importListStatusService.RecordFailure(Definition.Id); _logger.Warn("{0} {1}", this, ex.Message); } catch (RequestLimitReachedException) { - _netImportStatusService.RecordFailure(Definition.Id, TimeSpan.FromHours(1)); + _importListStatusService.RecordFailure(Definition.Id, TimeSpan.FromHours(1)); _logger.Warn("API Request Limit reached for {0}", this); } catch (CloudFlareCaptchaException ex) { - _netImportStatusService.RecordFailure(Definition.Id); + _importListStatusService.RecordFailure(Definition.Id); ex.WithData("FeedUrl", url); if (ex.IsExpired) { @@ -136,37 +136,29 @@ namespace NzbDrone.Core.NetImport _logger.Error(ex, "CAPTCHA token required for {0}, check import list settings.", this); } } - catch (NetImportException ex) + catch (ImportListException ex) { - _netImportStatusService.RecordFailure(Definition.Id); + _importListStatusService.RecordFailure(Definition.Id); _logger.Warn(ex, "{0}", url); } catch (Exception ex) { - _netImportStatusService.RecordFailure(Definition.Id); + _importListStatusService.RecordFailure(Definition.Id); ex.WithData("FeedUrl", url); _logger.Error(ex, "An error occurred while processing feed. {0}", url); } - return new NetImportFetchResult { Movies = movies, AnyFailure = anyFailure }; + return new ImportListFetchResult { Movies = CleanupListItems(movies), AnyFailure = anyFailure }; } - protected virtual IList FetchPage(NetImportRequest request, IParseNetImportResponse parser) + protected virtual IList FetchPage(ImportListRequest request, IParseImportListResponse parser) { - var response = FetchNetImportResponse(request); + var response = FetchImportListResponse(request); - return parser.ParseResponse(response).ToList().Select(m => - { - m.RootFolderPath = ((NetImportDefinition)Definition).RootFolderPath; - m.ProfileId = ((NetImportDefinition)Definition).ProfileId; - m.Monitored = ((NetImportDefinition)Definition).ShouldMonitor; - m.MinimumAvailability = ((NetImportDefinition)Definition).MinimumAvailability; - m.Tags = ((NetImportDefinition)Definition).Tags; - return m; - }).ToList(); + return parser.ParseResponse(response).ToList(); } - protected virtual NetImportResponse FetchNetImportResponse(NetImportRequest request) + protected virtual ImportListResponse FetchImportListResponse(ImportListRequest request) { _logger.Debug("Downloading List " + request.HttpRequest.ToString(false)); @@ -177,7 +169,7 @@ namespace NzbDrone.Core.NetImport request.HttpRequest.AllowAutoRedirect = true; - return new NetImportResponse(request, _httpClient.Execute(request.HttpRequest)); + return new ImportListResponse(request, _httpClient.Execute(request.HttpRequest)); } protected override void Test(List failures) @@ -204,11 +196,11 @@ namespace NzbDrone.Core.NetImport } catch (UnsupportedFeedException ex) { - _logger.Warn(ex, "Net Import feed is not supported"); + _logger.Warn(ex, "Import List feed is not supported"); - return new ValidationFailure(string.Empty, "Net Import feed is not supported: " + ex.Message); + return new ValidationFailure(string.Empty, "Import List feed is not supported: " + ex.Message); } - catch (NetImportException ex) + catch (ImportListException ex) { _logger.Warn(ex, "Unable to connect to list"); diff --git a/src/NzbDrone.Core/ImportLists/IImportList.cs b/src/NzbDrone.Core/ImportLists/IImportList.cs new file mode 100644 index 000000000..52be21a56 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/IImportList.cs @@ -0,0 +1,13 @@ +using NzbDrone.Core.ThingiProvider; + +namespace NzbDrone.Core.ImportLists +{ + public interface IImportList : IProvider + { + bool Enabled { get; } + bool EnableAuto { get; } + + ImportListType ListType { get; } + ImportListFetchResult Fetch(); + } +} diff --git a/src/NzbDrone.Core/ImportLists/IImportListRequestGenerator.cs b/src/NzbDrone.Core/ImportLists/IImportListRequestGenerator.cs new file mode 100644 index 000000000..228f76e0a --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/IImportListRequestGenerator.cs @@ -0,0 +1,7 @@ +namespace NzbDrone.Core.ImportLists +{ + public interface IImportListRequestGenerator + { + ImportListPageableRequestChain GetMovies(); + } +} diff --git a/src/NzbDrone.Core/ImportLists/IParseImportListResponse.cs b/src/NzbDrone.Core/ImportLists/IParseImportListResponse.cs new file mode 100644 index 000000000..0217024de --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/IParseImportListResponse.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using NzbDrone.Core.ImportLists.ImportListMovies; + +namespace NzbDrone.Core.ImportLists +{ + public interface IParseImportListResponse + { + IList ParseResponse(ImportListResponse importListResponse); + } +} diff --git a/src/NzbDrone.Core/NetImport/ImportExclusions/ImportExclusion.cs b/src/NzbDrone.Core/ImportLists/ImportExclusions/ImportExclusion.cs similarity index 87% rename from src/NzbDrone.Core/NetImport/ImportExclusions/ImportExclusion.cs rename to src/NzbDrone.Core/ImportLists/ImportExclusions/ImportExclusion.cs index afbd6a0c8..6ffa61a17 100644 --- a/src/NzbDrone.Core/NetImport/ImportExclusions/ImportExclusion.cs +++ b/src/NzbDrone.Core/ImportLists/ImportExclusions/ImportExclusion.cs @@ -1,6 +1,6 @@ using NzbDrone.Core.Datastore; -namespace NzbDrone.Core.NetImport.ImportExclusions +namespace NzbDrone.Core.ImportLists.ImportExclusions { public class ImportExclusion : ModelBase { diff --git a/src/NzbDrone.Core/NetImport/ImportExclusions/ImportExclusionsRepository.cs b/src/NzbDrone.Core/ImportLists/ImportExclusions/ImportExclusionsRepository.cs similarity index 93% rename from src/NzbDrone.Core/NetImport/ImportExclusions/ImportExclusionsRepository.cs rename to src/NzbDrone.Core/ImportLists/ImportExclusions/ImportExclusionsRepository.cs index 9c072991b..b3b7ff3e9 100644 --- a/src/NzbDrone.Core/NetImport/ImportExclusions/ImportExclusionsRepository.cs +++ b/src/NzbDrone.Core/ImportLists/ImportExclusions/ImportExclusionsRepository.cs @@ -2,7 +2,7 @@ using System.Linq; using NzbDrone.Core.Datastore; using NzbDrone.Core.Messaging.Events; -namespace NzbDrone.Core.NetImport.ImportExclusions +namespace NzbDrone.Core.ImportLists.ImportExclusions { public interface IImportExclusionsRepository : IBasicRepository { diff --git a/src/NzbDrone.Core/NetImport/ImportExclusions/ImportExclusionsService.cs b/src/NzbDrone.Core/ImportLists/ImportExclusions/ImportExclusionsService.cs similarity index 86% rename from src/NzbDrone.Core/NetImport/ImportExclusions/ImportExclusionsService.cs rename to src/NzbDrone.Core/ImportLists/ImportExclusions/ImportExclusionsService.cs index a938f1e72..7ebcec069 100644 --- a/src/NzbDrone.Core/NetImport/ImportExclusions/ImportExclusionsService.cs +++ b/src/NzbDrone.Core/ImportLists/ImportExclusions/ImportExclusionsService.cs @@ -4,7 +4,7 @@ using NLog; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Movies.Events; -namespace NzbDrone.Core.NetImport.ImportExclusions +namespace NzbDrone.Core.ImportLists.ImportExclusions { public interface IImportExclusionsService { @@ -14,6 +14,7 @@ namespace NzbDrone.Core.NetImport.ImportExclusions List AddExclusions(List exclusions); void RemoveExclusion(ImportExclusion exclusion); ImportExclusion GetById(int id); + ImportExclusion Update(ImportExclusion exclusion); } public class ImportExclusionsService : IImportExclusionsService, IHandleAsync @@ -65,11 +66,16 @@ namespace NzbDrone.Core.NetImport.ImportExclusions return _exclusionRepository.Get(id); } + public ImportExclusion Update(ImportExclusion exclusion) + { + return _exclusionRepository.Update(exclusion); + } + public void HandleAsync(MoviesDeletedEvent message) { if (message.AddExclusion) { - _logger.Debug("Adding {0} Deleted Movies to Net Import Exclusions", message.Movies.Count); + _logger.Debug("Adding {0} Deleted Movies to Import Exclusions", message.Movies.Count); _exclusionRepository.InsertMany(message.Movies.Select(m => new ImportExclusion { TmdbId = m.TmdbId, MovieTitle = m.Title, MovieYear = m.Year }).ToList()); } } diff --git a/src/NzbDrone.Core/NetImport/NetImportBase.cs b/src/NzbDrone.Core/ImportLists/ImportListBase.cs similarity index 66% rename from src/NzbDrone.Core/NetImport/NetImportBase.cs rename to src/NzbDrone.Core/ImportLists/ImportListBase.cs index b31ebab4b..2f989da93 100644 --- a/src/NzbDrone.Core/NetImport/NetImportBase.cs +++ b/src/NzbDrone.Core/ImportLists/ImportListBase.cs @@ -1,39 +1,45 @@ using System; using System.Collections.Generic; +using System.Linq; using FluentValidation.Results; using NLog; using NzbDrone.Core.Configuration; -using NzbDrone.Core.Movies; +using NzbDrone.Core.ImportLists.ImportListMovies; using NzbDrone.Core.Parser; using NzbDrone.Core.ThingiProvider; -namespace NzbDrone.Core.NetImport +namespace NzbDrone.Core.ImportLists { - public class NetImportFetchResult + public class ImportListFetchResult { - public IList Movies { get; set; } + public ImportListFetchResult() + { + Movies = new List(); + } + + public List Movies { get; set; } public bool AnyFailure { get; set; } } - public abstract class NetImportBase : INetImport + public abstract class ImportListBase : IImportList where TSettings : IProviderConfig, new() { - protected readonly INetImportStatusService _netImportStatusService; + protected readonly IImportListStatusService _importListStatusService; protected readonly IConfigService _configService; protected readonly IParsingService _parsingService; protected readonly Logger _logger; public abstract string Name { get; } - public abstract NetImportType ListType { get; } + public abstract ImportListType ListType { get; } public abstract bool Enabled { get; } public abstract bool EnableAuto { get; } - public abstract NetImportFetchResult Fetch(); + public abstract ImportListFetchResult Fetch(); - protected NetImportBase(INetImportStatusService netImportStatusService, IConfigService configService, IParsingService parsingService, Logger logger) + protected ImportListBase(IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, Logger logger) { - _netImportStatusService = netImportStatusService; + _importListStatusService = importListStatusService; _configService = configService; _parsingService = parsingService; _logger = logger; @@ -49,7 +55,7 @@ namespace NzbDrone.Core.NetImport { var config = (IProviderConfig)new TSettings(); - yield return new NetImportDefinition + yield return new ImportListDefinition { Name = GetType().Name, Enabled = config.Validate().IsValid && Enabled, @@ -67,6 +73,18 @@ namespace NzbDrone.Core.NetImport return null; } + protected virtual List CleanupListItems(IEnumerable listMovies) + { + var result = listMovies.ToList(); + + result.ForEach(c => + { + c.ListId = Definition.Id; + }); + + return result; + } + protected TSettings Settings => (TSettings)Definition.Settings; public ValidationResult Test() diff --git a/src/NzbDrone.Core/NetImport/NetImportBaseSettings.cs b/src/NzbDrone.Core/ImportLists/ImportListBaseSettings.cs similarity index 61% rename from src/NzbDrone.Core/NetImport/NetImportBaseSettings.cs rename to src/NzbDrone.Core/ImportLists/ImportListBaseSettings.cs index b03a897b4..53118c8c3 100644 --- a/src/NzbDrone.Core/NetImport/NetImportBaseSettings.cs +++ b/src/NzbDrone.Core/ImportLists/ImportListBaseSettings.cs @@ -3,21 +3,21 @@ using NzbDrone.Core.Annotations; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; -namespace NzbDrone.Core.NetImport +namespace NzbDrone.Core.ImportLists { - public class NetImportBaseSettingsValidator : AbstractValidator + public class ImportListBaseSettingsValidator : AbstractValidator { - public NetImportBaseSettingsValidator() + public ImportListBaseSettingsValidator() { RuleFor(c => c.Link).NotEmpty(); } } - public class NetImportBaseSettings : IProviderConfig + public class ImportListBaseSettings : IProviderConfig { - private static readonly NetImportBaseSettingsValidator Validator = new NetImportBaseSettingsValidator(); + private static readonly ImportListBaseSettingsValidator Validator = new ImportListBaseSettingsValidator(); - public NetImportBaseSettings() + public ImportListBaseSettings() { Link = "http://rss.imdb.com/list/"; } diff --git a/src/NzbDrone.Core/NetImport/NetImportDefinition.cs b/src/NzbDrone.Core/ImportLists/ImportListDefinition.cs similarity index 64% rename from src/NzbDrone.Core/NetImport/NetImportDefinition.cs rename to src/NzbDrone.Core/ImportLists/ImportListDefinition.cs index 1169a4974..97fadae36 100644 --- a/src/NzbDrone.Core/NetImport/NetImportDefinition.cs +++ b/src/NzbDrone.Core/ImportLists/ImportListDefinition.cs @@ -1,12 +1,12 @@ -using System.Collections.Generic; +using System.Collections.Generic; using NzbDrone.Core.Movies; using NzbDrone.Core.ThingiProvider; -namespace NzbDrone.Core.NetImport +namespace NzbDrone.Core.ImportLists { - public class NetImportDefinition : ProviderDefinition + public class ImportListDefinition : ProviderDefinition { - public NetImportDefinition() + public ImportListDefinition() { Tags = new HashSet(); } @@ -17,8 +17,9 @@ namespace NzbDrone.Core.NetImport public MovieStatusType MinimumAvailability { get; set; } public int ProfileId { get; set; } public string RootFolderPath { get; set; } + public bool SearchOnAdd { get; set; } public override bool Enable => Enabled; - public NetImportType ListType { get; set; } + public ImportListType ListType { get; set; } } } diff --git a/src/NzbDrone.Core/ImportLists/ImportListFactory.cs b/src/NzbDrone.Core/ImportLists/ImportListFactory.cs new file mode 100644 index 000000000..98d5fc762 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/ImportListFactory.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.Linq; +using NLog; +using NzbDrone.Common.Composition; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.ThingiProvider; + +namespace NzbDrone.Core.ImportLists +{ + public interface IImportListFactory : IProviderFactory + { + List Enabled(); + List Discoverable(); + } + + public class ImportListFactory : ProviderFactory, IImportListFactory + { + private readonly IImportListRepository _providerRepository; + private readonly Logger _logger; + + public ImportListFactory(IImportListRepository providerRepository, + IEnumerable providers, + IContainer container, + IEventAggregator eventAggregator, + Logger logger) + : base(providerRepository, providers, container, eventAggregator, logger) + { + _providerRepository = providerRepository; + _logger = logger; + } + + protected override List Active() + { + return base.Active().Where(c => c.Enabled).ToList(); + } + + public override void SetProviderCharacteristics(IImportList provider, ImportListDefinition definition) + { + base.SetProviderCharacteristics(provider, definition); + + definition.ListType = provider.ListType; + } + + public List Enabled() + { + var enabledImporters = GetAvailableProviders().Where(n => ((ImportListDefinition)n.Definition).Enabled); + return enabledImporters.ToList(); + } + + public List Discoverable() + { + var enabledImporters = GetAvailableProviders().Where(n => (n.GetType() == typeof(RadarrList.RadarrListImport) || n.GetType() == typeof(TMDb.Popular.TMDbPopularImport))); + return enabledImporters.ToList(); + } + } +} diff --git a/src/NzbDrone.Core/ImportLists/ImportListMovies/ImportListMovie.cs b/src/NzbDrone.Core/ImportLists/ImportListMovies/ImportListMovie.cs new file mode 100644 index 000000000..bd6fce955 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/ImportListMovies/ImportListMovie.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Movies; +using NzbDrone.Core.Movies.Translations; + +namespace NzbDrone.Core.ImportLists.ImportListMovies +{ + public class ImportListMovie : ModelBase + { + public ImportListMovie() + { + Images = new List(); + Genres = new List(); + Translations = new List(); + } + + public int TmdbId { get; set; } + public string ImdbId { get; set; } + public string Title { get; set; } + public string SortTitle { get; set; } + public MovieStatusType Status { get; set; } + public string Overview { get; set; } + public DateTime? LastInfoSync { get; set; } + public int Runtime { get; set; } + public List Images { get; set; } + public string Website { get; set; } + public int Year { get; set; } + public Ratings Ratings { get; set; } + public List Genres { get; set; } + + public MovieCollection Collection { get; set; } + + public string Certification { get; set; } + public DateTime? InCinemas { get; set; } + + public DateTime? PhysicalRelease { get; set; } + public DateTime? DigitalRelease { get; set; } + public List Translations { get; set; } + public string YouTubeTrailerId { get; set; } + public string Studio { get; set; } + public string OriginalTitle { get; set; } + public int ListId { get; set; } + } +} diff --git a/src/NzbDrone.Core/ImportLists/ImportListMovies/ImportListMovieRepository.cs b/src/NzbDrone.Core/ImportLists/ImportListMovies/ImportListMovieRepository.cs new file mode 100644 index 000000000..78afa8586 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/ImportListMovies/ImportListMovieRepository.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Messaging.Events; + +namespace NzbDrone.Core.ImportLists.ImportListMovies +{ + public interface IImportListMovieRepository : IBasicRepository + { + List GetAllForList(int listId); + } + + public class ImportListMovieRepository : BasicRepository, IImportListMovieRepository + { + public ImportListMovieRepository(IMainDatabase database, IEventAggregator eventAggregator) + : base(database, eventAggregator) + { + } + + public List GetAllForList(int listId) + { + return Query(x => x.ListId == listId); + } + } +} diff --git a/src/NzbDrone.Core/ImportLists/ImportListMovies/ImportListMovieService.cs b/src/NzbDrone.Core/ImportLists/ImportListMovies/ImportListMovieService.cs new file mode 100644 index 000000000..833c379bb --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/ImportListMovies/ImportListMovieService.cs @@ -0,0 +1,105 @@ +using System.Collections.Generic; +using System.Linq; +using NLog; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.ThingiProvider.Events; + +namespace NzbDrone.Core.ImportLists.ImportListMovies +{ + public interface IImportListMovieService + { + List GetAllListMovies(); + List GetAllForList(int listId); + ImportListMovie AddListMovie(ImportListMovie listMovie); + List AddListMovies(List listMovies); + List SyncMoviesForList(List listMovies, int listId); + void RemoveListMovie(ImportListMovie listMovie); + ImportListMovie GetById(int id); + } + + public class ImportListMovieService : IImportListMovieService, IHandleAsync> + { + private readonly IImportListMovieRepository _importListMovieRepository; + private readonly Logger _logger; + + public ImportListMovieService(IImportListMovieRepository importListMovieRepository, + Logger logger) + { + _importListMovieRepository = importListMovieRepository; + _logger = logger; + } + + public ImportListMovie AddListMovie(ImportListMovie exclusion) + { + return _importListMovieRepository.Insert(exclusion); + } + + public List AddListMovies(List listMovies) + { + _importListMovieRepository.InsertMany(listMovies); + + return listMovies; + } + + //public List SyncMoviesForList(List listMovies) + //{ + // var existingListMovies = GetAllListMovies(); + // var newMovies = listMovies.GroupBy(x => x.TmdbId); + + // listMovies = newMovies.Select(x => + // { + // var movie = x.First(); + + // movie.ListIds = x.SelectMany(m => m.ListIds).ToList(); + + // return movie; + // }).ToList(); + + // listMovies.ForEach(l => l.Id = existingListMovies.FirstOrDefault(e => e.TmdbId == l.TmdbId)?.Id ?? 0); + + // _listMovieRepository.InsertMany(listMovies.Where(l => l.Id == 0).ToList()); + // _listMovieRepository.UpdateMany(listMovies.Where(l => l.Id > 0).ToList()); + // _listMovieRepository.DeleteMany(existingListMovies.Where(l => !listMovies.Any(x => x.TmdbId == l.TmdbId)).ToList()); + + // return listMovies; + //} + public List SyncMoviesForList(List listMovies, int listId) + { + var existingListMovies = GetAllForList(listId); + + listMovies.ForEach(l => l.Id = existingListMovies.FirstOrDefault(e => e.TmdbId == l.TmdbId)?.Id ?? 0); + + _importListMovieRepository.InsertMany(listMovies.Where(l => l.Id == 0).ToList()); + _importListMovieRepository.UpdateMany(listMovies.Where(l => l.Id > 0).ToList()); + _importListMovieRepository.DeleteMany(existingListMovies.Where(l => !listMovies.Any(x => x.TmdbId == l.TmdbId)).ToList()); + + return listMovies; + } + + public List GetAllListMovies() + { + return _importListMovieRepository.All().ToList(); + } + + public List GetAllForList(int listId) + { + return _importListMovieRepository.GetAllForList(listId).ToList(); + } + + public void RemoveListMovie(ImportListMovie listMovie) + { + _importListMovieRepository.Delete(listMovie); + } + + public ImportListMovie GetById(int id) + { + return _importListMovieRepository.Get(id); + } + + public void HandleAsync(ProviderDeletedEvent message) + { + var moviesOnList = _importListMovieRepository.GetAllForList(message.ProviderId); + _importListMovieRepository.DeleteMany(moviesOnList); + } + } +} diff --git a/src/NzbDrone.Core/ImportLists/ImportListPageableRequest.cs b/src/NzbDrone.Core/ImportLists/ImportListPageableRequest.cs new file mode 100644 index 000000000..64b4fbe81 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/ImportListPageableRequest.cs @@ -0,0 +1,25 @@ +using System.Collections; +using System.Collections.Generic; + +namespace NzbDrone.Core.ImportLists +{ + public class ImportListPageableRequest : IEnumerable + { + private readonly IEnumerable _enumerable; + + public ImportListPageableRequest(IEnumerable enumerable) + { + _enumerable = enumerable; + } + + public IEnumerator GetEnumerator() + { + return _enumerable.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _enumerable.GetEnumerator(); + } + } +} diff --git a/src/NzbDrone.Core/ImportLists/ImportListPageableRequestChain.cs b/src/NzbDrone.Core/ImportLists/ImportListPageableRequestChain.cs new file mode 100644 index 000000000..9b2503c35 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/ImportListPageableRequestChain.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using System.Linq; + +namespace NzbDrone.Core.ImportLists +{ + public class ImportListPageableRequestChain + { + private List> _chains; + + public ImportListPageableRequestChain() + { + _chains = new List>(); + _chains.Add(new List()); + } + + public int Tiers => _chains.Count; + + public IEnumerable GetAllTiers() + { + return _chains.SelectMany(v => v); + } + + public IEnumerable GetTier(int index) + { + return _chains[index]; + } + + public void Add(IEnumerable request) + { + if (request == null) + { + return; + } + + _chains.Last().Add(new ImportListPageableRequest(request)); + } + + public void AddTier(IEnumerable request) + { + AddTier(); + Add(request); + } + + public void AddTier() + { + if (_chains.Last().Count == 0) + { + return; + } + + _chains.Add(new List()); + } + } +} diff --git a/src/NzbDrone.Core/ImportLists/ImportListRepository.cs b/src/NzbDrone.Core/ImportLists/ImportListRepository.cs new file mode 100644 index 000000000..9516c4441 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/ImportListRepository.cs @@ -0,0 +1,24 @@ +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.ThingiProvider; + +namespace NzbDrone.Core.ImportLists +{ + public interface IImportListRepository : IProviderRepository + { + void UpdateSettings(ImportListDefinition model); + } + + public class ImportListRepository : ProviderRepository, IImportListRepository + { + public ImportListRepository(IMainDatabase database, IEventAggregator eventAggregator) + : base(database, eventAggregator) + { + } + + public void UpdateSettings(ImportListDefinition model) + { + SetFields(model, m => m.Settings); + } + } +} diff --git a/src/NzbDrone.Core/NetImport/NetImportRequest.cs b/src/NzbDrone.Core/ImportLists/ImportListRequest.cs similarity index 60% rename from src/NzbDrone.Core/NetImport/NetImportRequest.cs rename to src/NzbDrone.Core/ImportLists/ImportListRequest.cs index e00fe316f..1a392f4da 100644 --- a/src/NzbDrone.Core/NetImport/NetImportRequest.cs +++ b/src/NzbDrone.Core/ImportLists/ImportListRequest.cs @@ -1,17 +1,17 @@ using NzbDrone.Common.Http; -namespace NzbDrone.Core.NetImport +namespace NzbDrone.Core.ImportLists { - public class NetImportRequest + public class ImportListRequest { public HttpRequest HttpRequest { get; private set; } - public NetImportRequest(string url, HttpAccept httpAccept) + public ImportListRequest(string url, HttpAccept httpAccept) { HttpRequest = new HttpRequest(url, httpAccept); } - public NetImportRequest(HttpRequest httpRequest) + public ImportListRequest(HttpRequest httpRequest) { HttpRequest = httpRequest; } diff --git a/src/NzbDrone.Core/NetImport/NetImportResponse.cs b/src/NzbDrone.Core/ImportLists/ImportListResponse.cs similarity index 52% rename from src/NzbDrone.Core/NetImport/NetImportResponse.cs rename to src/NzbDrone.Core/ImportLists/ImportListResponse.cs index 3174b0775..e81cfcf7e 100644 --- a/src/NzbDrone.Core/NetImport/NetImportResponse.cs +++ b/src/NzbDrone.Core/ImportLists/ImportListResponse.cs @@ -1,19 +1,19 @@ using NzbDrone.Common.Http; -namespace NzbDrone.Core.NetImport +namespace NzbDrone.Core.ImportLists { - public class NetImportResponse + public class ImportListResponse { - private readonly NetImportRequest _netImport; + private readonly ImportListRequest _importList; private readonly HttpResponse _httpResponse; - public NetImportResponse(NetImportRequest netImport, HttpResponse httpResponse) + public ImportListResponse(ImportListRequest importList, HttpResponse httpResponse) { - _netImport = netImport; + _importList = importList; _httpResponse = httpResponse; } - public NetImportRequest Request => _netImport; + public ImportListRequest Request => _importList; public HttpRequest HttpRequest => _httpResponse.Request; diff --git a/src/NzbDrone.Core/NetImport/NetImportStatus.cs b/src/NzbDrone.Core/ImportLists/ImportListStatus.cs similarity index 60% rename from src/NzbDrone.Core/NetImport/NetImportStatus.cs rename to src/NzbDrone.Core/ImportLists/ImportListStatus.cs index 640ab2b8f..3d590139a 100644 --- a/src/NzbDrone.Core/NetImport/NetImportStatus.cs +++ b/src/NzbDrone.Core/ImportLists/ImportListStatus.cs @@ -1,9 +1,9 @@ using NzbDrone.Core.Movies; using NzbDrone.Core.ThingiProvider.Status; -namespace NzbDrone.Core.NetImport +namespace NzbDrone.Core.ImportLists { - public class NetImportStatus : ProviderStatusBase + public class ImportListStatus : ProviderStatusBase { public Movie LastSyncListInfo { get; set; } } diff --git a/src/NzbDrone.Core/ImportLists/ImportListStatusRepository.cs b/src/NzbDrone.Core/ImportLists/ImportListStatusRepository.cs new file mode 100644 index 000000000..24d052dcc --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/ImportListStatusRepository.cs @@ -0,0 +1,18 @@ +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.ThingiProvider.Status; + +namespace NzbDrone.Core.ImportLists +{ + public interface IImportListStatusRepository : IProviderStatusRepository + { + } + + public class ImportListStatusRepository : ProviderStatusRepository, IImportListStatusRepository + { + public ImportListStatusRepository(IMainDatabase database, IEventAggregator eventAggregator) + : base(database, eventAggregator) + { + } + } +} diff --git a/src/NzbDrone.Core/NetImport/NetImportStatusService.cs b/src/NzbDrone.Core/ImportLists/ImportListStatusService.cs similarity index 68% rename from src/NzbDrone.Core/NetImport/NetImportStatusService.cs rename to src/NzbDrone.Core/ImportLists/ImportListStatusService.cs index 2f978a286..bea467650 100644 --- a/src/NzbDrone.Core/NetImport/NetImportStatusService.cs +++ b/src/NzbDrone.Core/ImportLists/ImportListStatusService.cs @@ -4,18 +4,18 @@ using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Movies; using NzbDrone.Core.ThingiProvider.Status; -namespace NzbDrone.Core.NetImport +namespace NzbDrone.Core.ImportLists { - public interface INetImportStatusService : IProviderStatusServiceBase + public interface IImportListStatusService : IProviderStatusServiceBase { Movie GetLastSyncListInfo(int importListId); void UpdateListSyncStatus(int importListId, Movie listItemInfo); } - public class NetImportStatusService : ProviderStatusServiceBase, INetImportStatusService + public class ImportListStatusService : ProviderStatusServiceBase, IImportListStatusService { - public NetImportStatusService(INetImportStatusRepository providerStatusRepository, IEventAggregator eventAggregator, IRuntimeInfo runtimeInfo, Logger logger) + public ImportListStatusService(IImportListStatusRepository providerStatusRepository, IEventAggregator eventAggregator, IRuntimeInfo runtimeInfo, Logger logger) : base(providerStatusRepository, eventAggregator, runtimeInfo, logger) { } diff --git a/src/NzbDrone.Core/ImportLists/ImportListSyncCommand.cs b/src/NzbDrone.Core/ImportLists/ImportListSyncCommand.cs new file mode 100644 index 000000000..9051d205f --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/ImportListSyncCommand.cs @@ -0,0 +1,24 @@ +using NzbDrone.Core.Messaging.Commands; + +namespace NzbDrone.Core.ImportLists +{ + public class ImportListSyncCommand : Command + { + public int? DefinitionId { get; set; } + + public ImportListSyncCommand() + { + } + + public ImportListSyncCommand(int? definition) + { + DefinitionId = definition; + } + + public override bool SendUpdatesToClient => true; + + public override bool IsTypeExclusive => true; + + public override bool UpdateScheduledTask => !DefinitionId.HasValue; + } +} diff --git a/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs b/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs new file mode 100644 index 000000000..7fb5a01ee --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs @@ -0,0 +1,217 @@ +using System.Collections.Generic; +using System.Linq; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Instrumentation.Extensions; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.ImportLists.ImportExclusions; +using NzbDrone.Core.ImportLists.ImportListMovies; +using NzbDrone.Core.Messaging.Commands; +using NzbDrone.Core.Movies; + +namespace NzbDrone.Core.ImportLists +{ + public class ImportListSyncService : IExecute + { + private readonly Logger _logger; + private readonly IImportListFactory _importListFactory; + private readonly IFetchAndParseImportList _listFetcherAndParser; + private readonly IMovieService _movieService; + private readonly IAddMovieService _addMovieService; + private readonly IConfigService _configService; + private readonly IImportExclusionsService _exclusionService; + + public ImportListSyncService(IImportListFactory importListFactory, + IFetchAndParseImportList listFetcherAndParser, + IMovieService movieService, + IAddMovieService addMovieService, + IConfigService configService, + IImportExclusionsService exclusionService, + Logger logger) + { + _importListFactory = importListFactory; + _listFetcherAndParser = listFetcherAndParser; + _movieService = movieService; + _addMovieService = addMovieService; + _exclusionService = exclusionService; + _logger = logger; + _configService = configService; + } + + private void SyncList(ImportListDefinition definition) + { + _logger.ProgressInfo(string.Format("Starting Import List Refresh for List {0}", definition.Name)); + + var result = _listFetcherAndParser.FetchSingleList(definition); + + ProcessReports(result); + } + + private void SyncAll() + { + var result = _listFetcherAndParser.Fetch(); + + if (_importListFactory.Enabled().Where(a => ((ImportListDefinition)a.Definition).EnableAuto).Empty()) + { + _logger.Info("No auto enabled lists, skipping sync and cleaning"); + return; + } + + if (!result.AnyFailure) + { + CleanLibrary(result.Movies.ToList()); + } + + ProcessReports(result); + } + + private void ProcessMovieReport(ImportListDefinition importList, ImportListMovie report, List listExclusions, List dbMovies, List moviesToAdd) + { + if (report.TmdbId == 0 || !importList.EnableAuto) + { + return; + } + + // Check to see if movie in DB + if (dbMovies.Contains(report.TmdbId)) + { + _logger.Debug("{0} [{1}] Rejected, Movie Exists in DB", report.TmdbId, report.Title); + return; + } + + // Check to see if movie excluded + var excludedMovie = listExclusions.Where(s => s.TmdbId == report.TmdbId).SingleOrDefault(); + + if (excludedMovie != null) + { + _logger.Debug("{0} [{1}] Rejected due to list exlcusion", report.TmdbId, report.Title); + return; + } + + // Append Artist if not already in DB or already on add list + if (moviesToAdd.All(s => s.TmdbId != report.TmdbId)) + { + var monitored = importList.ShouldMonitor; + + moviesToAdd.Add(new Movie + { + Monitored = monitored, + RootFolderPath = importList.RootFolderPath, + ProfileId = importList.ProfileId, + MinimumAvailability = importList.MinimumAvailability, + Tags = importList.Tags, + TmdbId = report.TmdbId, + Title = report.Title, + Year = report.Year, + ImdbId = report.ImdbId, + AddOptions = new AddMovieOptions + { + SearchForMovie = monitored && importList.SearchOnAdd, + } + }); + } + } + + private void ProcessReports(ImportListFetchResult listFetchResult) + { + listFetchResult.Movies = listFetchResult.Movies.DistinctBy(x => + { + if (x.TmdbId != 0) + { + return x.TmdbId.ToString(); + } + + if (x.ImdbId.IsNotNullOrWhiteSpace()) + { + return x.ImdbId; + } + + return x.Title; + }).ToList(); + + var listedMovies = listFetchResult.Movies.ToList(); + + var importExclusions = _exclusionService.GetAllExclusions(); + var dbMovies = _movieService.AllMovieTmdbIds(); + var moviesToAdd = new List(); + + var groupedMovies = listedMovies.GroupBy(x => x.ListId); + + foreach (var list in groupedMovies) + { + var importList = _importListFactory.Get(list.Key); + + foreach (var movie in list) + { + if (movie.TmdbId != 0) + { + ProcessMovieReport(importList, movie, importExclusions, dbMovies, moviesToAdd); + } + } + } + + if (moviesToAdd.Any()) + { + _logger.Info($"Adding {moviesToAdd.Count} movies from your auto enabled lists to library"); + } + + _addMovieService.AddMovies(moviesToAdd, true); + } + + public void Execute(ImportListSyncCommand message) + { + if (message.DefinitionId.HasValue) + { + SyncList(_importListFactory.Get(message.DefinitionId.Value)); + } + else + { + SyncAll(); + } + } + + private void CleanLibrary(List listMovies) + { + var moviesToUpdate = new List(); + + if (_configService.ListSyncLevel == "disabled") + { + return; + } + + // TODO use AllMovieTmdbIds here? + var moviesInLibrary = _movieService.GetAllMovies(); + foreach (var movie in moviesInLibrary) + { + var movieExists = listMovies.Any(c => c.TmdbId == movie.TmdbId || c.ImdbId == movie.ImdbId); + + if (!movieExists) + { + switch (_configService.ListSyncLevel) + { + case "logOnly": + _logger.Info("{0} was in your library, but not found in your lists --> You might want to unmonitor or remove it", movie); + break; + case "keepAndUnmonitor": + _logger.Info("{0} was in your library, but not found in your lists --> Keeping in library but Unmonitoring it", movie); + movie.Monitored = false; + moviesToUpdate.Add(movie); + break; + case "removeAndKeep": + _logger.Info("{0} was in your library, but not found in your lists --> Removing from library (keeping files)", movie); + _movieService.DeleteMovie(movie.Id, false); + break; + case "removeAndDelete": + _logger.Info("{0} was in your library, but not found in your lists --> Removing from library and deleting files", movie); + _movieService.DeleteMovie(movie.Id, true); + break; + default: + break; + } + } + } + + _movieService.UpdateMovie(moviesToUpdate, true); + } + } +} diff --git a/src/NzbDrone.Core/NetImport/NetImportType.cs b/src/NzbDrone.Core/ImportLists/ImportListType.cs similarity index 58% rename from src/NzbDrone.Core/NetImport/NetImportType.cs rename to src/NzbDrone.Core/ImportLists/ImportListType.cs index ea432592f..f31d835c2 100644 --- a/src/NzbDrone.Core/NetImport/NetImportType.cs +++ b/src/NzbDrone.Core/ImportLists/ImportListType.cs @@ -1,6 +1,6 @@ -namespace NzbDrone.Core.NetImport +namespace NzbDrone.Core.ImportLists { - public enum NetImportType + public enum ImportListType { Program, TMDB, diff --git a/src/NzbDrone.Core/ImportLists/ImportListUpdatedHandler.cs b/src/NzbDrone.Core/ImportLists/ImportListUpdatedHandler.cs new file mode 100644 index 000000000..64b126b18 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/ImportListUpdatedHandler.cs @@ -0,0 +1,26 @@ +using NzbDrone.Core.Messaging.Commands; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.ThingiProvider.Events; + +namespace NzbDrone.Core.ImportLists +{ + public class ImportListUpdatedHandler : IHandle>, IHandle> + { + private readonly IManageCommandQueue _commandQueueManager; + + public ImportListUpdatedHandler(IManageCommandQueue commandQueueManager) + { + _commandQueueManager = commandQueueManager; + } + + public void Handle(ProviderUpdatedEvent message) + { + _commandQueueManager.Push(new ImportListSyncCommand(message.Definition.Id)); + } + + public void Handle(ProviderAddedEvent message) + { + _commandQueueManager.Push(new ImportListSyncCommand(message.Definition.Id)); + } + } +} diff --git a/src/NzbDrone.Core/NetImport/RSSImport/RSSImport.cs b/src/NzbDrone.Core/ImportLists/RSSImport/RSSImport.cs similarity index 68% rename from src/NzbDrone.Core/NetImport/RSSImport/RSSImport.cs rename to src/NzbDrone.Core/ImportLists/RSSImport/RSSImport.cs index e373e1671..19f13cfee 100644 --- a/src/NzbDrone.Core/NetImport/RSSImport/RSSImport.cs +++ b/src/NzbDrone.Core/ImportLists/RSSImport/RSSImport.cs @@ -5,18 +5,18 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.Parser; using NzbDrone.Core.ThingiProvider; -namespace NzbDrone.Core.NetImport.RSSImport +namespace NzbDrone.Core.ImportLists.RSSImport { - public class RSSImport : HttpNetImportBase + public class RSSImport : HttpImportListBase { public override string Name => "RSS List"; - public override NetImportType ListType => NetImportType.Advanced; + public override ImportListType ListType => ImportListType.Advanced; public override bool Enabled => true; public override bool EnableAuto => false; - public RSSImport(IHttpClient httpClient, INetImportStatusService netImportStatusService, IConfigService configService, IParsingService parsingService, Logger logger) - : base(httpClient, netImportStatusService, configService, parsingService, logger) + public RSSImport(IHttpClient httpClient, IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, Logger logger) + : base(httpClient, importListStatusService, configService, parsingService, logger) { } @@ -29,7 +29,7 @@ namespace NzbDrone.Core.NetImport.RSSImport yield return def; } - yield return new NetImportDefinition + yield return new ImportListDefinition { Name = "IMDb List", Enabled = Enabled, @@ -38,7 +38,7 @@ namespace NzbDrone.Core.NetImport.RSSImport Implementation = GetType().Name, Settings = new RSSImportSettings { Link = "https://rss.imdb.com/list/YOURLISTID" }, }; - yield return new NetImportDefinition + yield return new ImportListDefinition { Name = "IMDb Watchlist", Enabled = Enabled, @@ -50,12 +50,12 @@ namespace NzbDrone.Core.NetImport.RSSImport } } - public override INetImportRequestGenerator GetRequestGenerator() + public override IImportListRequestGenerator GetRequestGenerator() { return new RSSImportRequestGenerator() { Settings = Settings }; } - public override IParseNetImportResponse GetParser() + public override IParseImportListResponse GetParser() { return new RSSImportParser(Settings, _logger); } diff --git a/src/NzbDrone.Core/NetImport/RSSImport/RSSImportParser.cs b/src/NzbDrone.Core/ImportLists/RSSImport/RSSImportParser.cs similarity index 78% rename from src/NzbDrone.Core/NetImport/RSSImport/RSSImportParser.cs rename to src/NzbDrone.Core/ImportLists/RSSImport/RSSImportParser.cs index 84f84cd42..e67e53ed2 100644 --- a/src/NzbDrone.Core/NetImport/RSSImport/RSSImportParser.cs +++ b/src/NzbDrone.Core/ImportLists/RSSImport/RSSImportParser.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -9,18 +9,18 @@ using System.Xml.Linq; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.ImportLists.Exceptions; +using NzbDrone.Core.ImportLists.ImportListMovies; using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers.Exceptions; -using NzbDrone.Core.Movies; -using NzbDrone.Core.NetImport.Exceptions; -namespace NzbDrone.Core.NetImport.RSSImport +namespace NzbDrone.Core.ImportLists.RSSImport { - public class RSSImportParser : IParseNetImportResponse + public class RSSImportParser : IParseImportListResponse { private readonly RSSImportSettings _settings; private readonly Logger _logger; - private NetImportResponse _importResponse; + private ImportListResponse _importResponse; private static readonly Regex ReplaceEntities = new Regex("&[a-z]+;", RegexOptions.Compiled | RegexOptions.IgnoreCase); @@ -31,11 +31,11 @@ namespace NzbDrone.Core.NetImport.RSSImport _logger = logger; } - public virtual IList ParseResponse(NetImportResponse importResponse) + public virtual IList ParseResponse(ImportListResponse importResponse) { _importResponse = importResponse; - var movies = new List(); + var movies = new List(); if (!PreProcess(importResponse)) { @@ -63,7 +63,7 @@ namespace NzbDrone.Core.NetImport.RSSImport return movies; } - protected virtual XDocument LoadXmlDocument(NetImportResponse indexerResponse) + protected virtual XDocument LoadXmlDocument(ImportListResponse indexerResponse) { try { @@ -100,28 +100,28 @@ namespace NzbDrone.Core.NetImport.RSSImport } } - protected virtual Movie CreateNewMovie() + protected virtual ImportListMovie CreateNewMovie() { - return new Movie(); + return new ImportListMovie(); } - protected virtual bool PreProcess(NetImportResponse netImportResponse) + protected virtual bool PreProcess(ImportListResponse importListResponse) { - if (netImportResponse.HttpResponse.StatusCode != HttpStatusCode.OK) + if (importListResponse.HttpResponse.StatusCode != HttpStatusCode.OK) { - throw new NetImportException(netImportResponse, "List API call resulted in an unexpected StatusCode [{0}]", netImportResponse.HttpResponse.StatusCode); + throw new ImportListException(importListResponse, "List API call resulted in an unexpected StatusCode [{0}]", importListResponse.HttpResponse.StatusCode); } - if (netImportResponse.HttpResponse.Headers.ContentType != null && netImportResponse.HttpResponse.Headers.ContentType.Contains("text/html") && - netImportResponse.HttpRequest.Headers.Accept != null && !netImportResponse.HttpRequest.Headers.Accept.Contains("text/html")) + if (importListResponse.HttpResponse.Headers.ContentType != null && importListResponse.HttpResponse.Headers.ContentType.Contains("text/html") && + importListResponse.HttpRequest.Headers.Accept != null && !importListResponse.HttpRequest.Headers.Accept.Contains("text/html")) { - throw new NetImportException(netImportResponse, "List responded with html content. Site is likely blocked or unavailable."); + throw new ImportListException(importListResponse, "List responded with html content. Site is likely blocked or unavailable."); } return true; } - protected Movie ProcessItem(XElement item) + protected ImportListMovie ProcessItem(XElement item) { var releaseInfo = CreateNewMovie(); @@ -131,7 +131,7 @@ namespace NzbDrone.Core.NetImport.RSSImport return PostProcess(item, releaseInfo); } - protected virtual Movie ProcessItem(XElement item, Movie releaseInfo) + protected virtual ImportListMovie ProcessItem(XElement item, ImportListMovie releaseInfo) { var title = GetTitle(item); @@ -166,7 +166,7 @@ namespace NzbDrone.Core.NetImport.RSSImport return releaseInfo; } - protected virtual Movie PostProcess(XElement item, Movie releaseInfo) + protected virtual ImportListMovie PostProcess(XElement item, ImportListMovie releaseInfo) { return releaseInfo; } diff --git a/src/NzbDrone.Core/ImportLists/RSSImport/RSSImportRequestGenerator.cs b/src/NzbDrone.Core/ImportLists/RSSImport/RSSImportRequestGenerator.cs new file mode 100644 index 000000000..d4a786c73 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/RSSImport/RSSImportRequestGenerator.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using NzbDrone.Common.Http; + +namespace NzbDrone.Core.ImportLists.RSSImport +{ + public class RSSImportRequestGenerator : IImportListRequestGenerator + { + public RSSImportSettings Settings { get; set; } + + public virtual ImportListPageableRequestChain GetMovies() + { + var pageableRequests = new ImportListPageableRequestChain(); + + pageableRequests.Add(GetMovies(null)); + + return pageableRequests; + } + + //public ImportListPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + //{ + // return new ImportListPageableRequestChain(); + //} + private IEnumerable GetMovies(string searchParameters) + { + var request = new ImportListRequest($"{Settings.Link.Trim()}", HttpAccept.Rss); + yield return request; + } + } +} diff --git a/src/NzbDrone.Core/NetImport/RSSImport/RSSImportSettings.cs b/src/NzbDrone.Core/ImportLists/RSSImport/RSSImportSettings.cs similarity index 95% rename from src/NzbDrone.Core/NetImport/RSSImport/RSSImportSettings.cs rename to src/NzbDrone.Core/ImportLists/RSSImport/RSSImportSettings.cs index f02b55344..874e923f0 100644 --- a/src/NzbDrone.Core/NetImport/RSSImport/RSSImportSettings.cs +++ b/src/NzbDrone.Core/ImportLists/RSSImport/RSSImportSettings.cs @@ -3,7 +3,7 @@ using NzbDrone.Core.Annotations; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; -namespace NzbDrone.Core.NetImport.RSSImport +namespace NzbDrone.Core.ImportLists.RSSImport { public class RSSImportSettingsValidator : AbstractValidator { diff --git a/src/NzbDrone.Core/NetImport/Radarr/RadarrAPIResource.cs b/src/NzbDrone.Core/ImportLists/Radarr/RadarrAPIResource.cs similarity index 95% rename from src/NzbDrone.Core/NetImport/Radarr/RadarrAPIResource.cs rename to src/NzbDrone.Core/ImportLists/Radarr/RadarrAPIResource.cs index 69b967098..1a6b43725 100644 --- a/src/NzbDrone.Core/NetImport/Radarr/RadarrAPIResource.cs +++ b/src/NzbDrone.Core/ImportLists/Radarr/RadarrAPIResource.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace NzbDrone.Core.NetImport.Radarr +namespace NzbDrone.Core.ImportLists.Radarr { public class RadarrMovie { diff --git a/src/NzbDrone.Core/NetImport/Radarr/RadarrImport.cs b/src/NzbDrone.Core/ImportLists/Radarr/RadarrImport.cs similarity index 75% rename from src/NzbDrone.Core/NetImport/Radarr/RadarrImport.cs rename to src/NzbDrone.Core/ImportLists/Radarr/RadarrImport.cs index 7b44577cd..3b6e6eff6 100644 --- a/src/NzbDrone.Core/NetImport/Radarr/RadarrImport.cs +++ b/src/NzbDrone.Core/ImportLists/Radarr/RadarrImport.cs @@ -5,34 +5,34 @@ using FluentValidation.Results; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Core.Configuration; -using NzbDrone.Core.Movies; +using NzbDrone.Core.ImportLists.ImportListMovies; using NzbDrone.Core.Parser; using NzbDrone.Core.Validation; -namespace NzbDrone.Core.NetImport.Radarr +namespace NzbDrone.Core.ImportLists.Radarr { - public class RadarrImport : NetImportBase + public class RadarrImport : ImportListBase { private readonly IRadarrV3Proxy _radarrV3Proxy; public override string Name => "Radarr"; public override bool Enabled => true; public override bool EnableAuto => false; - public override NetImportType ListType => NetImportType.Program; + public override ImportListType ListType => ImportListType.Program; public RadarrImport(IRadarrV3Proxy radarrV3Proxy, - INetImportStatusService netImportStatusService, + IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, Logger logger) - : base(netImportStatusService, configService, parsingService, logger) + : base(importListStatusService, configService, parsingService, logger) { _radarrV3Proxy = radarrV3Proxy; } - public override NetImportFetchResult Fetch() + public override ImportListFetchResult Fetch() { - var movies = new List(); + var movies = new List(); var anyFailure = false; try @@ -44,35 +44,29 @@ namespace NzbDrone.Core.NetImport.Radarr if ((!Settings.ProfileIds.Any() || Settings.ProfileIds.Contains(remoteMovie.QualityProfileId)) && (!Settings.TagIds.Any() || Settings.TagIds.Any(x => remoteMovie.Tags.Any(y => y == x)))) { - movies.Add(new Movie + movies.Add(new ImportListMovie { TmdbId = remoteMovie.TmdbId, Title = remoteMovie.Title, SortTitle = remoteMovie.SortTitle, - TitleSlug = remoteMovie.TitleSlug, Overview = remoteMovie.Overview, Images = remoteMovie.Images.Select(x => MapImage(x, Settings.BaseUrl)).ToList(), PhysicalRelease = remoteMovie.PhysicalRelease, InCinemas = remoteMovie.InCinemas, - Year = remoteMovie.Year, - RootFolderPath = ((NetImportDefinition)Definition).RootFolderPath, - ProfileId = ((NetImportDefinition)Definition).ProfileId, - Monitored = ((NetImportDefinition)Definition).ShouldMonitor, - MinimumAvailability = ((NetImportDefinition)Definition).MinimumAvailability, - Tags = ((NetImportDefinition)Definition).Tags + Year = remoteMovie.Year }); } } - _netImportStatusService.RecordSuccess(Definition.Id); + _importListStatusService.RecordSuccess(Definition.Id); } catch { anyFailure = true; - _netImportStatusService.RecordFailure(Definition.Id); + _importListStatusService.RecordFailure(Definition.Id); } - return new NetImportFetchResult { Movies = movies, AnyFailure = anyFailure }; + return new ImportListFetchResult { Movies = CleanupListItems(movies), AnyFailure = anyFailure }; } public override object RequestAction(string action, IDictionary query) diff --git a/src/NzbDrone.Core/NetImport/Radarr/RadarrSettings.cs b/src/NzbDrone.Core/ImportLists/Radarr/RadarrSettings.cs similarity index 97% rename from src/NzbDrone.Core/NetImport/Radarr/RadarrSettings.cs rename to src/NzbDrone.Core/ImportLists/Radarr/RadarrSettings.cs index 095ee1b4f..ee2778d20 100644 --- a/src/NzbDrone.Core/NetImport/Radarr/RadarrSettings.cs +++ b/src/NzbDrone.Core/ImportLists/Radarr/RadarrSettings.cs @@ -4,7 +4,7 @@ using NzbDrone.Core.Annotations; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; -namespace NzbDrone.Core.NetImport.Radarr +namespace NzbDrone.Core.ImportLists.Radarr { public class RadarrSettingsValidator : AbstractValidator { diff --git a/src/NzbDrone.Core/NetImport/Radarr/RadarrV3Proxy.cs b/src/NzbDrone.Core/ImportLists/Radarr/RadarrV3Proxy.cs similarity index 98% rename from src/NzbDrone.Core/NetImport/Radarr/RadarrV3Proxy.cs rename to src/NzbDrone.Core/ImportLists/Radarr/RadarrV3Proxy.cs index ce23e962c..d4c930213 100644 --- a/src/NzbDrone.Core/NetImport/Radarr/RadarrV3Proxy.cs +++ b/src/NzbDrone.Core/ImportLists/Radarr/RadarrV3Proxy.cs @@ -7,7 +7,7 @@ using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; -namespace NzbDrone.Core.NetImport.Radarr +namespace NzbDrone.Core.ImportLists.Radarr { public interface IRadarrV3Proxy { diff --git a/src/NzbDrone.Core/NetImport/RadarrList/RadarrListException.cs b/src/NzbDrone.Core/ImportLists/RadarrList/RadarrListException.cs similarity index 96% rename from src/NzbDrone.Core/NetImport/RadarrList/RadarrListException.cs rename to src/NzbDrone.Core/ImportLists/RadarrList/RadarrListException.cs index aec6be251..f8b6004b0 100644 --- a/src/NzbDrone.Core/NetImport/RadarrList/RadarrListException.cs +++ b/src/NzbDrone.Core/ImportLists/RadarrList/RadarrListException.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; -namespace NzbDrone.Core.NetImport.RadarrList +namespace NzbDrone.Core.ImportLists.RadarrList { public class RadarrListException : Exception { diff --git a/src/NzbDrone.Core/NetImport/RadarrList/RadarrListImport.cs b/src/NzbDrone.Core/ImportLists/RadarrList/RadarrListImport.cs similarity index 68% rename from src/NzbDrone.Core/NetImport/RadarrList/RadarrListImport.cs rename to src/NzbDrone.Core/ImportLists/RadarrList/RadarrListImport.cs index 0d45f0e1d..bb118158f 100644 --- a/src/NzbDrone.Core/NetImport/RadarrList/RadarrListImport.cs +++ b/src/NzbDrone.Core/ImportLists/RadarrList/RadarrListImport.cs @@ -5,22 +5,22 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.Parser; using NzbDrone.Core.ThingiProvider; -namespace NzbDrone.Core.NetImport.RadarrList +namespace NzbDrone.Core.ImportLists.RadarrList { - public class RadarrListImport : HttpNetImportBase + public class RadarrListImport : HttpImportListBase { public override string Name => "Custom Lists"; - public override NetImportType ListType => NetImportType.Advanced; + public override ImportListType ListType => ImportListType.Advanced; public override bool Enabled => true; public override bool EnableAuto => false; public RadarrListImport(IHttpClient httpClient, - INetImportStatusService netImportStatusService, + IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, Logger logger) - : base(httpClient, netImportStatusService, configService, parsingService, logger) + : base(httpClient, importListStatusService, configService, parsingService, logger) { } @@ -35,7 +35,7 @@ namespace NzbDrone.Core.NetImport.RadarrList } } - public override INetImportRequestGenerator GetRequestGenerator() + public override IImportListRequestGenerator GetRequestGenerator() { return new RadarrListRequestGenerator() { @@ -45,7 +45,7 @@ namespace NzbDrone.Core.NetImport.RadarrList }; } - public override IParseNetImportResponse GetParser() + public override IParseImportListResponse GetParser() { return new RadarrListParser(); } diff --git a/src/NzbDrone.Core/NetImport/RadarrList/RadarrListParser.cs b/src/NzbDrone.Core/ImportLists/RadarrList/RadarrListParser.cs similarity index 56% rename from src/NzbDrone.Core/NetImport/RadarrList/RadarrListParser.cs rename to src/NzbDrone.Core/ImportLists/RadarrList/RadarrListParser.cs index 0f12f2510..29231930d 100644 --- a/src/NzbDrone.Core/NetImport/RadarrList/RadarrListParser.cs +++ b/src/NzbDrone.Core/ImportLists/RadarrList/RadarrListParser.cs @@ -2,22 +2,22 @@ using System.Collections.Generic; using Newtonsoft.Json; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; -using NzbDrone.Core.Movies; -using NzbDrone.Core.NetImport.TMDb; +using NzbDrone.Core.ImportLists.ImportListMovies; +using NzbDrone.Core.ImportLists.TMDb; -namespace NzbDrone.Core.NetImport.RadarrList +namespace NzbDrone.Core.ImportLists.RadarrList { - public class RadarrListParser : IParseNetImportResponse + public class RadarrListParser : IParseImportListResponse { public RadarrListParser() { } - public IList ParseResponse(NetImportResponse netMovieImporterResponse) + public IList ParseResponse(ImportListResponse importListResponse) { - var importResponse = netMovieImporterResponse; + var importResponse = importListResponse; - var movies = new List(); + var movies = new List(); if (!PreProcess(importResponse)) { @@ -32,14 +32,14 @@ namespace NzbDrone.Core.NetImport.RadarrList return movies; } - return jsonResponse.SelectList(m => new Movie { TmdbId = m.Id }); + return jsonResponse.SelectList(m => new ImportListMovie { TmdbId = m.Id }); } - protected virtual bool PreProcess(NetImportResponse netImportResponse) + protected virtual bool PreProcess(ImportListResponse importListResponse) { try { - var error = JsonConvert.DeserializeObject(netImportResponse.HttpResponse.Content); + var error = JsonConvert.DeserializeObject(importListResponse.HttpResponse.Content); if (error != null && error.Errors != null && error.Errors.Count != 0) { @@ -51,9 +51,9 @@ namespace NzbDrone.Core.NetImport.RadarrList //No error! } - if (netImportResponse.HttpResponse.StatusCode != System.Net.HttpStatusCode.OK) + if (importListResponse.HttpResponse.StatusCode != System.Net.HttpStatusCode.OK) { - throw new HttpException(netImportResponse.HttpRequest, netImportResponse.HttpResponse); + throw new HttpException(importListResponse.HttpRequest, importListResponse.HttpResponse); } return true; diff --git a/src/NzbDrone.Core/ImportLists/RadarrList/RadarrListRequestGenerator.cs b/src/NzbDrone.Core/ImportLists/RadarrList/RadarrListRequestGenerator.cs new file mode 100644 index 000000000..ab2464eae --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/RadarrList/RadarrListRequestGenerator.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using NLog; +using NzbDrone.Common.Http; + +namespace NzbDrone.Core.ImportLists.RadarrList +{ + public class RadarrListRequestGenerator : IImportListRequestGenerator + { + public RadarrListSettings Settings { get; set; } + public IHttpClient HttpClient { get; set; } + public Logger Logger { get; set; } + + public virtual ImportListPageableRequestChain GetMovies() + { + var pageableRequests = new ImportListPageableRequestChain(); + + var request = new ImportListRequest(Settings.Url, HttpAccept.Json); + + request.HttpRequest.SuppressHttpError = true; + + pageableRequests.Add(new List { request }); + return pageableRequests; + } + } +} diff --git a/src/NzbDrone.Core/NetImport/RadarrList/RadarrListSettings.cs b/src/NzbDrone.Core/ImportLists/RadarrList/RadarrListSettings.cs similarity index 94% rename from src/NzbDrone.Core/NetImport/RadarrList/RadarrListSettings.cs rename to src/NzbDrone.Core/ImportLists/RadarrList/RadarrListSettings.cs index 5c03aec8e..d6e1c6731 100644 --- a/src/NzbDrone.Core/NetImport/RadarrList/RadarrListSettings.cs +++ b/src/NzbDrone.Core/ImportLists/RadarrList/RadarrListSettings.cs @@ -3,7 +3,7 @@ using NzbDrone.Core.Annotations; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; -namespace NzbDrone.Core.NetImport.RadarrList +namespace NzbDrone.Core.ImportLists.RadarrList { public class RadarrSettingsValidator : AbstractValidator { diff --git a/src/NzbDrone.Core/NetImport/RadarrList2/IMDb/IMDbListImport.cs b/src/NzbDrone.Core/ImportLists/RadarrList2/IMDb/IMDbListImport.cs similarity index 77% rename from src/NzbDrone.Core/NetImport/RadarrList2/IMDb/IMDbListImport.cs rename to src/NzbDrone.Core/ImportLists/RadarrList2/IMDb/IMDbListImport.cs index 55e60180f..14d437d78 100644 --- a/src/NzbDrone.Core/NetImport/RadarrList2/IMDb/IMDbListImport.cs +++ b/src/NzbDrone.Core/ImportLists/RadarrList2/IMDb/IMDbListImport.cs @@ -6,25 +6,25 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.Parser; using NzbDrone.Core.ThingiProvider; -namespace NzbDrone.Core.NetImport.RadarrList2.IMDbList +namespace NzbDrone.Core.ImportLists.RadarrList2.IMDbList { - public class IMDbListImport : HttpNetImportBase + public class IMDbListImport : HttpImportListBase { private readonly IHttpRequestBuilderFactory _radarrMetadata; public override string Name => "IMDb Lists"; - public override NetImportType ListType => NetImportType.Other; + public override ImportListType ListType => ImportListType.Other; public override bool Enabled => true; public override bool EnableAuto => false; public IMDbListImport(IRadarrCloudRequestBuilder requestBuilder, IHttpClient httpClient, - INetImportStatusService netImportStatusService, + IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, Logger logger) - : base(httpClient, netImportStatusService, configService, parsingService, logger) + : base(httpClient, importListStatusService, configService, parsingService, logger) { _radarrMetadata = requestBuilder.RadarrMetadata; } @@ -38,7 +38,7 @@ namespace NzbDrone.Core.NetImport.RadarrList2.IMDbList yield return def; } - yield return new NetImportDefinition + yield return new ImportListDefinition { Name = "IMDb Top 250", Enabled = Enabled, @@ -47,7 +47,7 @@ namespace NzbDrone.Core.NetImport.RadarrList2.IMDbList Implementation = GetType().Name, Settings = new IMDbListSettings { ListId = "top250" }, }; - yield return new NetImportDefinition + yield return new ImportListDefinition { Name = "IMDb Popular Movies", Enabled = Enabled, @@ -59,7 +59,7 @@ namespace NzbDrone.Core.NetImport.RadarrList2.IMDbList } } - public override INetImportRequestGenerator GetRequestGenerator() + public override IImportListRequestGenerator GetRequestGenerator() { return new IMDbListRequestGenerator() { @@ -70,7 +70,7 @@ namespace NzbDrone.Core.NetImport.RadarrList2.IMDbList }; } - public override IParseNetImportResponse GetParser() + public override IParseImportListResponse GetParser() { return new RadarrList2Parser(); } diff --git a/src/NzbDrone.Core/NetImport/RadarrList2/IMDb/IMDbListRequestGenerator.cs b/src/NzbDrone.Core/ImportLists/RadarrList2/IMDb/IMDbListRequestGenerator.cs similarity index 87% rename from src/NzbDrone.Core/NetImport/RadarrList2/IMDb/IMDbListRequestGenerator.cs rename to src/NzbDrone.Core/ImportLists/RadarrList2/IMDb/IMDbListRequestGenerator.cs index 122ae9de8..bfdb27487 100644 --- a/src/NzbDrone.Core/NetImport/RadarrList2/IMDb/IMDbListRequestGenerator.cs +++ b/src/NzbDrone.Core/ImportLists/RadarrList2/IMDb/IMDbListRequestGenerator.cs @@ -1,6 +1,6 @@ using NzbDrone.Common.Http; -namespace NzbDrone.Core.NetImport.RadarrList2.IMDbList +namespace NzbDrone.Core.ImportLists.RadarrList2.IMDbList { public class IMDbListRequestGenerator : RadarrList2RequestGeneratorBase { diff --git a/src/NzbDrone.Core/NetImport/RadarrList2/IMDb/IMDbListSettings.cs b/src/NzbDrone.Core/ImportLists/RadarrList2/IMDb/IMDbListSettings.cs similarity index 95% rename from src/NzbDrone.Core/NetImport/RadarrList2/IMDb/IMDbListSettings.cs rename to src/NzbDrone.Core/ImportLists/RadarrList2/IMDb/IMDbListSettings.cs index 7483d29b2..6308f2049 100644 --- a/src/NzbDrone.Core/NetImport/RadarrList2/IMDb/IMDbListSettings.cs +++ b/src/NzbDrone.Core/ImportLists/RadarrList2/IMDb/IMDbListSettings.cs @@ -3,7 +3,7 @@ using NzbDrone.Core.Annotations; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; -namespace NzbDrone.Core.NetImport.RadarrList2.IMDbList +namespace NzbDrone.Core.ImportLists.RadarrList2.IMDbList { public class IMDbSettingsValidator : AbstractValidator { diff --git a/src/NzbDrone.Core/NetImport/RadarrList2/RadarrList2Parser.cs b/src/NzbDrone.Core/ImportLists/RadarrList2/RadarrList2Parser.cs similarity index 64% rename from src/NzbDrone.Core/NetImport/RadarrList2/RadarrList2Parser.cs rename to src/NzbDrone.Core/ImportLists/RadarrList2/RadarrList2Parser.cs index c38bcd4ac..9ce49a558 100644 --- a/src/NzbDrone.Core/NetImport/RadarrList2/RadarrList2Parser.cs +++ b/src/NzbDrone.Core/ImportLists/RadarrList2/RadarrList2Parser.cs @@ -2,19 +2,19 @@ using System.Collections.Generic; using System.Net; using Newtonsoft.Json; using NzbDrone.Common.Extensions; +using NzbDrone.Core.ImportLists.Exceptions; +using NzbDrone.Core.ImportLists.ImportListMovies; using NzbDrone.Core.MetadataSource.SkyHook.Resource; -using NzbDrone.Core.Movies; -using NzbDrone.Core.NetImport.Exceptions; -namespace NzbDrone.Core.NetImport.RadarrList2 +namespace NzbDrone.Core.ImportLists.RadarrList2 { - public class RadarrList2Parser : IParseNetImportResponse + public class RadarrList2Parser : IParseImportListResponse { - public IList ParseResponse(NetImportResponse netMovieImporterResponse) + public IList ParseResponse(ImportListResponse importListResponse) { - var importResponse = netMovieImporterResponse; + var importResponse = importListResponse; - var movies = new List(); + var movies = new List(); if (!PreProcess(importResponse)) { @@ -29,14 +29,14 @@ namespace NzbDrone.Core.NetImport.RadarrList2 return movies; } - return jsonResponse.SelectList(m => new Movie { TmdbId = m.TmdbId }); + return jsonResponse.SelectList(m => new ImportListMovie { TmdbId = m.TmdbId }); } - protected virtual bool PreProcess(NetImportResponse listResponse) + protected virtual bool PreProcess(ImportListResponse listResponse) { if (listResponse.HttpResponse.StatusCode != HttpStatusCode.OK) { - throw new NetImportException(listResponse, + throw new ImportListException(listResponse, "Radarr API call resulted in an unexpected StatusCode [{0}]", listResponse.HttpResponse.StatusCode); } @@ -46,7 +46,7 @@ namespace NzbDrone.Core.NetImport.RadarrList2 listResponse.HttpRequest.Headers.Accept != null && !listResponse.HttpRequest.Headers.Accept.Contains("text/json")) { - throw new NetImportException(listResponse, + throw new ImportListException(listResponse, "Radarr API responded with html content. Site is likely blocked or unavailable."); } diff --git a/src/NzbDrone.Core/NetImport/RadarrList2/RadarrList2RequestGenerator.cs b/src/NzbDrone.Core/ImportLists/RadarrList2/RadarrList2RequestGenerator.cs similarity index 52% rename from src/NzbDrone.Core/NetImport/RadarrList2/RadarrList2RequestGenerator.cs rename to src/NzbDrone.Core/ImportLists/RadarrList2/RadarrList2RequestGenerator.cs index d2f3b8dd9..ea0ca7320 100644 --- a/src/NzbDrone.Core/NetImport/RadarrList2/RadarrList2RequestGenerator.cs +++ b/src/NzbDrone.Core/ImportLists/RadarrList2/RadarrList2RequestGenerator.cs @@ -2,9 +2,9 @@ using NLog; using NzbDrone.Common.Http; -namespace NzbDrone.Core.NetImport.RadarrList2 +namespace NzbDrone.Core.ImportLists.RadarrList2 { - public abstract class RadarrList2RequestGeneratorBase : INetImportRequestGenerator + public abstract class RadarrList2RequestGeneratorBase : IImportListRequestGenerator { public IHttpRequestBuilderFactory RequestBuilder { get; set; } public IHttpClient HttpClient { get; set; } @@ -12,17 +12,17 @@ namespace NzbDrone.Core.NetImport.RadarrList2 protected abstract HttpRequest GetHttpRequest(); - public virtual NetImportPageableRequestChain GetMovies() + public virtual ImportListPageableRequestChain GetMovies() { - var pageableRequests = new NetImportPageableRequestChain(); + var pageableRequests = new ImportListPageableRequestChain(); var httpRequest = GetHttpRequest(); - var request = new NetImportRequest(httpRequest.Url.ToString(), HttpAccept.Json); + var request = new ImportListRequest(httpRequest.Url.ToString(), HttpAccept.Json); request.HttpRequest.SuppressHttpError = true; - pageableRequests.Add(new List { request }); + pageableRequests.Add(new List { request }); return pageableRequests; } } diff --git a/src/NzbDrone.Core/NetImport/RadarrList2/StevenLu/StevenLu2Import.cs b/src/NzbDrone.Core/ImportLists/RadarrList2/StevenLu/StevenLu2Import.cs similarity index 67% rename from src/NzbDrone.Core/NetImport/RadarrList2/StevenLu/StevenLu2Import.cs rename to src/NzbDrone.Core/ImportLists/RadarrList2/StevenLu/StevenLu2Import.cs index 0e4a0116f..1c0368b50 100644 --- a/src/NzbDrone.Core/NetImport/RadarrList2/StevenLu/StevenLu2Import.cs +++ b/src/NzbDrone.Core/ImportLists/RadarrList2/StevenLu/StevenLu2Import.cs @@ -4,30 +4,30 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; using NzbDrone.Core.Parser; -namespace NzbDrone.Core.NetImport.RadarrList2.StevenLu +namespace NzbDrone.Core.ImportLists.RadarrList2.StevenLu { - public class StevenLu2Import : HttpNetImportBase + public class StevenLu2Import : HttpImportListBase { private readonly IHttpRequestBuilderFactory _radarrMetadata; public override string Name => "StevenLu List"; - public override NetImportType ListType => NetImportType.Other; + public override ImportListType ListType => ImportListType.Other; public override bool Enabled => true; public override bool EnableAuto => false; public StevenLu2Import(IRadarrCloudRequestBuilder requestBuilder, IHttpClient httpClient, - INetImportStatusService netImportStatusService, + IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, Logger logger) - : base(httpClient, netImportStatusService, configService, parsingService, logger) + : base(httpClient, importListStatusService, configService, parsingService, logger) { _radarrMetadata = requestBuilder.RadarrMetadata; } - public override INetImportRequestGenerator GetRequestGenerator() + public override IImportListRequestGenerator GetRequestGenerator() { return new StevenLu2RequestGenerator() { @@ -38,7 +38,7 @@ namespace NzbDrone.Core.NetImport.RadarrList2.StevenLu }; } - public override IParseNetImportResponse GetParser() + public override IParseImportListResponse GetParser() { return new RadarrList2Parser(); } diff --git a/src/NzbDrone.Core/NetImport/RadarrList2/StevenLu/StevenLu2RequestGenerator.cs b/src/NzbDrone.Core/ImportLists/RadarrList2/StevenLu/StevenLu2RequestGenerator.cs similarity index 93% rename from src/NzbDrone.Core/NetImport/RadarrList2/StevenLu/StevenLu2RequestGenerator.cs rename to src/NzbDrone.Core/ImportLists/RadarrList2/StevenLu/StevenLu2RequestGenerator.cs index 6f3b6bfd5..da8702a9b 100644 --- a/src/NzbDrone.Core/NetImport/RadarrList2/StevenLu/StevenLu2RequestGenerator.cs +++ b/src/NzbDrone.Core/ImportLists/RadarrList2/StevenLu/StevenLu2RequestGenerator.cs @@ -1,6 +1,6 @@ using NzbDrone.Common.Http; -namespace NzbDrone.Core.NetImport.RadarrList2.StevenLu +namespace NzbDrone.Core.ImportLists.RadarrList2.StevenLu { public class StevenLu2RequestGenerator : RadarrList2RequestGeneratorBase { diff --git a/src/NzbDrone.Core/NetImport/RadarrList2/StevenLu/StevenLu2Settings.cs b/src/NzbDrone.Core/ImportLists/RadarrList2/StevenLu/StevenLu2Settings.cs similarity index 95% rename from src/NzbDrone.Core/NetImport/RadarrList2/StevenLu/StevenLu2Settings.cs rename to src/NzbDrone.Core/ImportLists/RadarrList2/StevenLu/StevenLu2Settings.cs index 6d2eef6a2..7013abd26 100644 --- a/src/NzbDrone.Core/NetImport/RadarrList2/StevenLu/StevenLu2Settings.cs +++ b/src/NzbDrone.Core/ImportLists/RadarrList2/StevenLu/StevenLu2Settings.cs @@ -3,7 +3,7 @@ using NzbDrone.Core.Annotations; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; -namespace NzbDrone.Core.NetImport.RadarrList2.StevenLu +namespace NzbDrone.Core.ImportLists.RadarrList2.StevenLu { public class StevenLu2SettingsValidator : AbstractValidator { diff --git a/src/NzbDrone.Core/NetImport/StevenLu/StevenLuAPI.cs b/src/NzbDrone.Core/ImportLists/StevenLu/StevenLuAPI.cs similarity index 79% rename from src/NzbDrone.Core/NetImport/StevenLu/StevenLuAPI.cs rename to src/NzbDrone.Core/ImportLists/StevenLu/StevenLuAPI.cs index 8ebc4726e..68be95532 100644 --- a/src/NzbDrone.Core/NetImport/StevenLu/StevenLuAPI.cs +++ b/src/NzbDrone.Core/ImportLists/StevenLu/StevenLuAPI.cs @@ -1,4 +1,4 @@ -namespace NzbDrone.Core.NetImport.StevenLu +namespace NzbDrone.Core.ImportLists.StevenLu { public class StevenLuResponse { diff --git a/src/NzbDrone.Core/NetImport/StevenLu/StevenLuImport.cs b/src/NzbDrone.Core/ImportLists/StevenLu/StevenLuImport.cs similarity index 57% rename from src/NzbDrone.Core/NetImport/StevenLu/StevenLuImport.cs rename to src/NzbDrone.Core/ImportLists/StevenLu/StevenLuImport.cs index 2c849f458..f04d94bf9 100644 --- a/src/NzbDrone.Core/NetImport/StevenLu/StevenLuImport.cs +++ b/src/NzbDrone.Core/ImportLists/StevenLu/StevenLuImport.cs @@ -3,31 +3,31 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; using NzbDrone.Core.Parser; -namespace NzbDrone.Core.NetImport.StevenLu +namespace NzbDrone.Core.ImportLists.StevenLu { - public class StevenLuImport : HttpNetImportBase + public class StevenLuImport : HttpImportListBase { public override string Name => "StevenLu Custom"; - public override NetImportType ListType => NetImportType.Advanced; + public override ImportListType ListType => ImportListType.Advanced; public override bool Enabled => true; public override bool EnableAuto => false; public StevenLuImport(IHttpClient httpClient, - INetImportStatusService netImportStatusService, + IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, Logger logger) - : base(httpClient, netImportStatusService, configService, parsingService, logger) + : base(httpClient, importListStatusService, configService, parsingService, logger) { } - public override INetImportRequestGenerator GetRequestGenerator() + public override IImportListRequestGenerator GetRequestGenerator() { return new StevenLuRequestGenerator() { Settings = Settings }; } - public override IParseNetImportResponse GetParser() + public override IParseImportListResponse GetParser() { return new StevenLuParser(); } diff --git a/src/NzbDrone.Core/ImportLists/StevenLu/StevenLuParser.cs b/src/NzbDrone.Core/ImportLists/StevenLu/StevenLuParser.cs new file mode 100644 index 000000000..5be54a240 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/StevenLu/StevenLuParser.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; +using System.Net; +using Newtonsoft.Json; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.ImportLists.Exceptions; +using NzbDrone.Core.ImportLists.ImportListMovies; + +namespace NzbDrone.Core.ImportLists.StevenLu +{ + public class StevenLuParser : IParseImportListResponse + { + private ImportListResponse _importResponse; + + public StevenLuParser() + { + } + + public IList ParseResponse(ImportListResponse importResponse) + { + _importResponse = importResponse; + + var movies = new List(); + + if (!PreProcess(_importResponse)) + { + return movies; + } + + var jsonResponse = JsonConvert.DeserializeObject>(_importResponse.Content); + + // no movies were return + if (jsonResponse == null) + { + return movies; + } + + foreach (var item in jsonResponse) + { + movies.AddIfNotNull(new ImportListMovie() + { + Title = item.title, + ImdbId = item.imdb_id, + }); + } + + return movies; + } + + protected virtual bool PreProcess(ImportListResponse importListResponse) + { + if (importListResponse.HttpResponse.StatusCode != HttpStatusCode.OK) + { + throw new ImportListException(importListResponse, "StevenLu API call resulted in an unexpected StatusCode [{0}]", importListResponse.HttpResponse.StatusCode); + } + + if (importListResponse.HttpResponse.Headers.ContentType != null && importListResponse.HttpResponse.Headers.ContentType.Contains("text/json") && + importListResponse.HttpRequest.Headers.Accept != null && !importListResponse.HttpRequest.Headers.Accept.Contains("text/json")) + { + throw new ImportListException(importListResponse, "StevenLu responded with html content. Site is likely blocked or unavailable."); + } + + return true; + } + } +} diff --git a/src/NzbDrone.Core/ImportLists/StevenLu/StevenLuRequestGenerator.cs b/src/NzbDrone.Core/ImportLists/StevenLu/StevenLuRequestGenerator.cs new file mode 100644 index 000000000..02f690402 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/StevenLu/StevenLuRequestGenerator.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using NzbDrone.Common.Http; + +namespace NzbDrone.Core.ImportLists.StevenLu +{ + public class StevenLuRequestGenerator : IImportListRequestGenerator + { + public StevenLuSettings Settings { get; set; } + + public virtual ImportListPageableRequestChain GetMovies() + { + var pageableRequests = new ImportListPageableRequestChain(); + pageableRequests.Add(GetMovies(null)); + return pageableRequests; + } + + private IEnumerable GetMovies(string searchParameters) + { + var request = new ImportListRequest($"{Settings.Link.Trim()}", HttpAccept.Json); + yield return request; + } + } +} diff --git a/src/NzbDrone.Core/NetImport/StevenLu/StevenLuSettings.cs b/src/NzbDrone.Core/ImportLists/StevenLu/StevenLuSettings.cs similarity index 95% rename from src/NzbDrone.Core/NetImport/StevenLu/StevenLuSettings.cs rename to src/NzbDrone.Core/ImportLists/StevenLu/StevenLuSettings.cs index cbc8c2c67..c68c666ad 100644 --- a/src/NzbDrone.Core/NetImport/StevenLu/StevenLuSettings.cs +++ b/src/NzbDrone.Core/ImportLists/StevenLu/StevenLuSettings.cs @@ -3,7 +3,7 @@ using NzbDrone.Core.Annotations; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; -namespace NzbDrone.Core.NetImport.StevenLu +namespace NzbDrone.Core.ImportLists.StevenLu { public class StevenLuSettingsValidator : AbstractValidator { diff --git a/src/NzbDrone.Core/NetImport/TMDb/Collection/TMDbCollectionImport.cs b/src/NzbDrone.Core/ImportLists/TMDb/Collection/TMDbCollectionImport.cs similarity index 69% rename from src/NzbDrone.Core/NetImport/TMDb/Collection/TMDbCollectionImport.cs rename to src/NzbDrone.Core/ImportLists/TMDb/Collection/TMDbCollectionImport.cs index 8e39bbc9e..a7f691c13 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/Collection/TMDbCollectionImport.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/Collection/TMDbCollectionImport.cs @@ -5,18 +5,18 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.MetadataSource; using NzbDrone.Core.Parser; -namespace NzbDrone.Core.NetImport.TMDb.Collection +namespace NzbDrone.Core.ImportLists.TMDb.Collection { - public class TMDbCollectionImport : TMDbNetImportBase + public class TMDbCollectionImport : TMDbImportListBase { public TMDbCollectionImport(IRadarrCloudRequestBuilder requestBuilder, IHttpClient httpClient, - INetImportStatusService netImportStatusService, + IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, ISearchForNewMovie searchForNewMovie, Logger logger) - : base(requestBuilder, httpClient, netImportStatusService, configService, parsingService, searchForNewMovie, logger) + : base(requestBuilder, httpClient, importListStatusService, configService, parsingService, searchForNewMovie, logger) { } @@ -24,12 +24,12 @@ namespace NzbDrone.Core.NetImport.TMDb.Collection public override bool Enabled => true; public override bool EnableAuto => false; - public override IParseNetImportResponse GetParser() + public override IParseImportListResponse GetParser() { return new TMDbCollectionParser(); } - public override INetImportRequestGenerator GetRequestGenerator() + public override IImportListRequestGenerator GetRequestGenerator() { return new TMDbCollectionRequestGenerator() { diff --git a/src/NzbDrone.Core/NetImport/TMDb/Collection/TMDbCollectionParser.cs b/src/NzbDrone.Core/ImportLists/TMDb/Collection/TMDbCollectionParser.cs similarity index 77% rename from src/NzbDrone.Core/NetImport/TMDb/Collection/TMDbCollectionParser.cs rename to src/NzbDrone.Core/ImportLists/TMDb/Collection/TMDbCollectionParser.cs index f92f795ee..b97f29e7c 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/Collection/TMDbCollectionParser.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/Collection/TMDbCollectionParser.cs @@ -1,15 +1,15 @@ using System.Collections.Generic; using Newtonsoft.Json; using NzbDrone.Common.Extensions; -using NzbDrone.Core.Movies; +using NzbDrone.Core.ImportLists.ImportListMovies; -namespace NzbDrone.Core.NetImport.TMDb.Collection +namespace NzbDrone.Core.ImportLists.TMDb.Collection { public class TMDbCollectionParser : TMDbParser { - public override IList ParseResponse(NetImportResponse importResponse) + public override IList ParseResponse(ImportListResponse importResponse) { - var movies = new List(); + var movies = new List(); if (!PreProcess(importResponse)) { diff --git a/src/NzbDrone.Core/NetImport/TMDb/Collection/TMDbCollectionRequestGenerator.cs b/src/NzbDrone.Core/ImportLists/TMDb/Collection/TMDbCollectionRequestGenerator.cs similarity index 72% rename from src/NzbDrone.Core/NetImport/TMDb/Collection/TMDbCollectionRequestGenerator.cs rename to src/NzbDrone.Core/ImportLists/TMDb/Collection/TMDbCollectionRequestGenerator.cs index b48b828ab..10ac3342a 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/Collection/TMDbCollectionRequestGenerator.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/Collection/TMDbCollectionRequestGenerator.cs @@ -2,9 +2,9 @@ using NLog; using NzbDrone.Common.Http; -namespace NzbDrone.Core.NetImport.TMDb.Collection +namespace NzbDrone.Core.ImportLists.TMDb.Collection { - public class TMDbCollectionRequestGenerator : INetImportRequestGenerator + public class TMDbCollectionRequestGenerator : IImportListRequestGenerator { public TMDbCollectionSettings Settings { get; set; } public IHttpClient HttpClient { get; set; } @@ -15,20 +15,20 @@ namespace NzbDrone.Core.NetImport.TMDb.Collection { } - public virtual NetImportPageableRequestChain GetMovies() + public virtual ImportListPageableRequestChain GetMovies() { - var pageableRequests = new NetImportPageableRequestChain(); + var pageableRequests = new ImportListPageableRequestChain(); pageableRequests.Add(GetMoviesRequest()); return pageableRequests; } - private IEnumerable GetMoviesRequest() + private IEnumerable GetMoviesRequest() { Logger.Info($"Importing TMDb movies from collection: {Settings.CollectionId}"); - yield return new NetImportRequest(RequestBuilder.Create() + yield return new ImportListRequest(RequestBuilder.Create() .SetSegment("api", "3") .SetSegment("route", "collection") .SetSegment("id", Settings.CollectionId) diff --git a/src/NzbDrone.Core/NetImport/TMDb/Collection/TMDbCollectionSettings.cs b/src/NzbDrone.Core/ImportLists/TMDb/Collection/TMDbCollectionSettings.cs similarity index 94% rename from src/NzbDrone.Core/NetImport/TMDb/Collection/TMDbCollectionSettings.cs rename to src/NzbDrone.Core/ImportLists/TMDb/Collection/TMDbCollectionSettings.cs index 92d95d3f4..59200a39f 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/Collection/TMDbCollectionSettings.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/Collection/TMDbCollectionSettings.cs @@ -2,7 +2,7 @@ using FluentValidation; using NzbDrone.Core.Annotations; -namespace NzbDrone.Core.NetImport.TMDb.Collection +namespace NzbDrone.Core.ImportLists.TMDb.Collection { public class TMDbCollectionSettingsValidator : TMDbSettingsBaseValidator { diff --git a/src/NzbDrone.Core/NetImport/TMDb/List/TMDbListImport.cs b/src/NzbDrone.Core/ImportLists/TMDb/List/TMDbListImport.cs similarity index 69% rename from src/NzbDrone.Core/NetImport/TMDb/List/TMDbListImport.cs rename to src/NzbDrone.Core/ImportLists/TMDb/List/TMDbListImport.cs index 286669636..c8a87a038 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/List/TMDbListImport.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/List/TMDbListImport.cs @@ -5,18 +5,18 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.MetadataSource; using NzbDrone.Core.Parser; -namespace NzbDrone.Core.NetImport.TMDb.List +namespace NzbDrone.Core.ImportLists.TMDb.List { - public class TMDbListImport : TMDbNetImportBase + public class TMDbListImport : TMDbImportListBase { public TMDbListImport(IRadarrCloudRequestBuilder requestBuilder, IHttpClient httpClient, - INetImportStatusService netImportStatusService, + IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, ISearchForNewMovie searchForNewMovie, Logger logger) - : base(requestBuilder, httpClient, netImportStatusService, configService, parsingService, searchForNewMovie, logger) + : base(requestBuilder, httpClient, importListStatusService, configService, parsingService, searchForNewMovie, logger) { } @@ -24,12 +24,12 @@ namespace NzbDrone.Core.NetImport.TMDb.List public override bool Enabled => true; public override bool EnableAuto => false; - public override IParseNetImportResponse GetParser() + public override IParseImportListResponse GetParser() { return new TMDbListParser(); } - public override INetImportRequestGenerator GetRequestGenerator() + public override IImportListRequestGenerator GetRequestGenerator() { return new TMDbListRequestGenerator() { diff --git a/src/NzbDrone.Core/NetImport/TMDb/List/TMDbListParser.cs b/src/NzbDrone.Core/ImportLists/TMDb/List/TMDbListParser.cs similarity index 77% rename from src/NzbDrone.Core/NetImport/TMDb/List/TMDbListParser.cs rename to src/NzbDrone.Core/ImportLists/TMDb/List/TMDbListParser.cs index 61c6c9909..4d4f834ee 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/List/TMDbListParser.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/List/TMDbListParser.cs @@ -1,15 +1,15 @@ using System.Collections.Generic; using Newtonsoft.Json; using NzbDrone.Common.Extensions; -using NzbDrone.Core.Movies; +using NzbDrone.Core.ImportLists.ImportListMovies; -namespace NzbDrone.Core.NetImport.TMDb.List +namespace NzbDrone.Core.ImportLists.TMDb.List { public class TMDbListParser : TMDbParser { - public override IList ParseResponse(NetImportResponse importResponse) + public override IList ParseResponse(ImportListResponse importResponse) { - var movies = new List(); + var movies = new List(); if (!PreProcess(importResponse)) { diff --git a/src/NzbDrone.Core/NetImport/TMDb/List/TMDbListRequestGenerator.cs b/src/NzbDrone.Core/ImportLists/TMDb/List/TMDbListRequestGenerator.cs similarity index 71% rename from src/NzbDrone.Core/NetImport/TMDb/List/TMDbListRequestGenerator.cs rename to src/NzbDrone.Core/ImportLists/TMDb/List/TMDbListRequestGenerator.cs index 6454404b4..aac6bd5f8 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/List/TMDbListRequestGenerator.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/List/TMDbListRequestGenerator.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using NLog; using NzbDrone.Common.Http; -namespace NzbDrone.Core.NetImport.TMDb.List +namespace NzbDrone.Core.ImportLists.TMDb.List { - public class TMDbListRequestGenerator : INetImportRequestGenerator + public class TMDbListRequestGenerator : IImportListRequestGenerator { public TMDbListSettings Settings { get; set; } public IHttpClient HttpClient { get; set; } @@ -15,16 +15,16 @@ namespace NzbDrone.Core.NetImport.TMDb.List { } - public virtual NetImportPageableRequestChain GetMovies() + public virtual ImportListPageableRequestChain GetMovies() { - var pageableRequests = new NetImportPageableRequestChain(); + var pageableRequests = new ImportListPageableRequestChain(); pageableRequests.Add(GetMoviesRequest()); return pageableRequests; } - private IEnumerable GetMoviesRequest() + private IEnumerable GetMoviesRequest() { Logger.Info($"Importing TMDb movies from list: {Settings.ListId}"); @@ -34,7 +34,7 @@ namespace NzbDrone.Core.NetImport.TMDb.List .SetSegment("id", Settings.ListId) .SetSegment("secondaryRoute", ""); - yield return new NetImportRequest(requestBuilder.Accept(HttpAccept.Json) + yield return new ImportListRequest(requestBuilder.Accept(HttpAccept.Json) .Build()); } } diff --git a/src/NzbDrone.Core/NetImport/TMDb/List/TMDbListSettings.cs b/src/NzbDrone.Core/ImportLists/TMDb/List/TMDbListSettings.cs similarity index 94% rename from src/NzbDrone.Core/NetImport/TMDb/List/TMDbListSettings.cs rename to src/NzbDrone.Core/ImportLists/TMDb/List/TMDbListSettings.cs index 823a3e3ed..78137b6c5 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/List/TMDbListSettings.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/List/TMDbListSettings.cs @@ -1,7 +1,7 @@ using FluentValidation; using NzbDrone.Core.Annotations; -namespace NzbDrone.Core.NetImport.TMDb.List +namespace NzbDrone.Core.ImportLists.TMDb.List { public class TMDbListSettingsValidator : TMDbSettingsBaseValidator { diff --git a/src/NzbDrone.Core/NetImport/TMDb/Person/TMDbPersonImport.cs b/src/NzbDrone.Core/ImportLists/TMDb/Person/TMDbPersonImport.cs similarity index 69% rename from src/NzbDrone.Core/NetImport/TMDb/Person/TMDbPersonImport.cs rename to src/NzbDrone.Core/ImportLists/TMDb/Person/TMDbPersonImport.cs index 2f9c4f624..aa09d299c 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/Person/TMDbPersonImport.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/Person/TMDbPersonImport.cs @@ -5,18 +5,18 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.MetadataSource; using NzbDrone.Core.Parser; -namespace NzbDrone.Core.NetImport.TMDb.Person +namespace NzbDrone.Core.ImportLists.TMDb.Person { - public class TMDbPersonImport : TMDbNetImportBase + public class TMDbPersonImport : TMDbImportListBase { public TMDbPersonImport(IRadarrCloudRequestBuilder requestBuilder, IHttpClient httpClient, - INetImportStatusService netImportStatusService, + IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, ISearchForNewMovie searchForNewMovie, Logger logger) - : base(requestBuilder, httpClient, netImportStatusService, configService, parsingService, searchForNewMovie, logger) + : base(requestBuilder, httpClient, importListStatusService, configService, parsingService, searchForNewMovie, logger) { } @@ -24,12 +24,12 @@ namespace NzbDrone.Core.NetImport.TMDb.Person public override bool Enabled => true; public override bool EnableAuto => false; - public override IParseNetImportResponse GetParser() + public override IParseImportListResponse GetParser() { return new TMDbPersonParser(Settings); } - public override INetImportRequestGenerator GetRequestGenerator() + public override IImportListRequestGenerator GetRequestGenerator() { return new TMDbPersonRequestGenerator() { diff --git a/src/NzbDrone.Core/NetImport/TMDb/Person/TMDbPersonParser.cs b/src/NzbDrone.Core/ImportLists/TMDb/Person/TMDbPersonParser.cs similarity index 84% rename from src/NzbDrone.Core/NetImport/TMDb/Person/TMDbPersonParser.cs rename to src/NzbDrone.Core/ImportLists/TMDb/Person/TMDbPersonParser.cs index 909a066e3..08a25aeec 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/Person/TMDbPersonParser.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/Person/TMDbPersonParser.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using Newtonsoft.Json; using NzbDrone.Common.Extensions; -using NzbDrone.Core.Movies; +using NzbDrone.Core.ImportLists.ImportListMovies; -namespace NzbDrone.Core.NetImport.TMDb.Person +namespace NzbDrone.Core.ImportLists.TMDb.Person { public class TMDbPersonParser : TMDbParser { @@ -14,9 +14,9 @@ namespace NzbDrone.Core.NetImport.TMDb.Person _settings = settings; } - public override IList ParseResponse(NetImportResponse importResponse) + public override IList ParseResponse(ImportListResponse importResponse) { - var movies = new List(); + var movies = new List(); if (!PreProcess(importResponse)) { @@ -43,7 +43,7 @@ namespace NzbDrone.Core.NetImport.TMDb.Person continue; } - movies.AddIfNotNull(new Movie { TmdbId = movie.Id }); + movies.AddIfNotNull(new ImportListMovie { TmdbId = movie.Id }); } } @@ -59,7 +59,7 @@ namespace NzbDrone.Core.NetImport.TMDb.Person if (crewTypes.Contains(movie.Department)) { - movies.AddIfNotNull(new Movie { TmdbId = movie.Id }); + movies.AddIfNotNull(new ImportListMovie { TmdbId = movie.Id }); } } } diff --git a/src/NzbDrone.Core/NetImport/TMDb/Person/TMDbPersonRequestGenerator.cs b/src/NzbDrone.Core/ImportLists/TMDb/Person/TMDbPersonRequestGenerator.cs similarity index 71% rename from src/NzbDrone.Core/NetImport/TMDb/Person/TMDbPersonRequestGenerator.cs rename to src/NzbDrone.Core/ImportLists/TMDb/Person/TMDbPersonRequestGenerator.cs index e240f3fe4..09ca6164a 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/Person/TMDbPersonRequestGenerator.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/Person/TMDbPersonRequestGenerator.cs @@ -2,9 +2,9 @@ using NLog; using NzbDrone.Common.Http; -namespace NzbDrone.Core.NetImport.TMDb.Person +namespace NzbDrone.Core.ImportLists.TMDb.Person { - public class TMDbPersonRequestGenerator : INetImportRequestGenerator + public class TMDbPersonRequestGenerator : IImportListRequestGenerator { public TMDbPersonSettings Settings { get; set; } public IHttpClient HttpClient { get; set; } @@ -15,16 +15,16 @@ namespace NzbDrone.Core.NetImport.TMDb.Person { } - public virtual NetImportPageableRequestChain GetMovies() + public virtual ImportListPageableRequestChain GetMovies() { - var pageableRequests = new NetImportPageableRequestChain(); + var pageableRequests = new ImportListPageableRequestChain(); pageableRequests.Add(GetMoviesRequest()); return pageableRequests; } - private IEnumerable GetMoviesRequest() + private IEnumerable GetMoviesRequest() { Logger.Info($"Importing TMDb movies from person: {Settings.PersonId}"); @@ -34,7 +34,7 @@ namespace NzbDrone.Core.NetImport.TMDb.Person .SetSegment("id", Settings.PersonId) .SetSegment("secondaryRoute", "/movie_credits"); - yield return new NetImportRequest(requestBuilder.Accept(HttpAccept.Json) + yield return new ImportListRequest(requestBuilder.Accept(HttpAccept.Json) .Build()); } } diff --git a/src/NzbDrone.Core/NetImport/TMDb/Person/TMDbPersonSettings.cs b/src/NzbDrone.Core/ImportLists/TMDb/Person/TMDbPersonSettings.cs similarity index 97% rename from src/NzbDrone.Core/NetImport/TMDb/Person/TMDbPersonSettings.cs rename to src/NzbDrone.Core/ImportLists/TMDb/Person/TMDbPersonSettings.cs index aa67fe7b8..ade0a1421 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/Person/TMDbPersonSettings.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/Person/TMDbPersonSettings.cs @@ -2,7 +2,7 @@ using FluentValidation; using NzbDrone.Core.Annotations; -namespace NzbDrone.Core.NetImport.TMDb.Person +namespace NzbDrone.Core.ImportLists.TMDb.Person { public class TMDbPersonSettingsValidator : TMDbSettingsBaseValidator { diff --git a/src/NzbDrone.Core/NetImport/TMDb/Popular/TMDbPopularImport.cs b/src/NzbDrone.Core/ImportLists/TMDb/Popular/TMDbPopularImport.cs similarity index 69% rename from src/NzbDrone.Core/NetImport/TMDb/Popular/TMDbPopularImport.cs rename to src/NzbDrone.Core/ImportLists/TMDb/Popular/TMDbPopularImport.cs index bf2f9ffc4..4a064d4b7 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/Popular/TMDbPopularImport.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/Popular/TMDbPopularImport.cs @@ -5,18 +5,18 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.MetadataSource; using NzbDrone.Core.Parser; -namespace NzbDrone.Core.NetImport.TMDb.Popular +namespace NzbDrone.Core.ImportLists.TMDb.Popular { - public class TMDbPopularImport : TMDbNetImportBase + public class TMDbPopularImport : TMDbImportListBase { public TMDbPopularImport(IRadarrCloudRequestBuilder requestBuilder, IHttpClient httpClient, - INetImportStatusService netImportStatusService, + IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, ISearchForNewMovie searchForNewMovie, Logger logger) - : base(requestBuilder, httpClient, netImportStatusService, configService, parsingService, searchForNewMovie, logger) + : base(requestBuilder, httpClient, importListStatusService, configService, parsingService, searchForNewMovie, logger) { } @@ -24,12 +24,12 @@ namespace NzbDrone.Core.NetImport.TMDb.Popular public override bool Enabled => true; public override bool EnableAuto => false; - public override IParseNetImportResponse GetParser() + public override IParseImportListResponse GetParser() { return new TMDbParser(); } - public override INetImportRequestGenerator GetRequestGenerator() + public override IImportListRequestGenerator GetRequestGenerator() { return new TMDbPopularRequestGenerator() { diff --git a/src/NzbDrone.Core/NetImport/TMDb/Popular/TMDbPopularListType.cs b/src/NzbDrone.Core/ImportLists/TMDb/Popular/TMDbPopularListType.cs similarity index 87% rename from src/NzbDrone.Core/NetImport/TMDb/Popular/TMDbPopularListType.cs rename to src/NzbDrone.Core/ImportLists/TMDb/Popular/TMDbPopularListType.cs index 2b99953b2..baba4d0b5 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/Popular/TMDbPopularListType.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/Popular/TMDbPopularListType.cs @@ -1,6 +1,6 @@ using System.Runtime.Serialization; -namespace NzbDrone.Core.NetImport.TMDb.Popular +namespace NzbDrone.Core.ImportLists.TMDb.Popular { public enum TMDbPopularListType { diff --git a/src/NzbDrone.Core/NetImport/TMDb/Popular/TMDbPopularRequestGenerator.cs b/src/NzbDrone.Core/ImportLists/TMDb/Popular/TMDbPopularRequestGenerator.cs similarity index 90% rename from src/NzbDrone.Core/NetImport/TMDb/Popular/TMDbPopularRequestGenerator.cs rename to src/NzbDrone.Core/ImportLists/TMDb/Popular/TMDbPopularRequestGenerator.cs index f354e2762..473af3b46 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/Popular/TMDbPopularRequestGenerator.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/Popular/TMDbPopularRequestGenerator.cs @@ -4,9 +4,9 @@ using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; -namespace NzbDrone.Core.NetImport.TMDb.Popular +namespace NzbDrone.Core.ImportLists.TMDb.Popular { - public class TMDbPopularRequestGenerator : INetImportRequestGenerator + public class TMDbPopularRequestGenerator : IImportListRequestGenerator { public TMDbPopularSettings Settings { get; set; } public IHttpClient HttpClient { get; set; } @@ -20,16 +20,16 @@ namespace NzbDrone.Core.NetImport.TMDb.Popular MaxPages = 3; } - public virtual NetImportPageableRequestChain GetMovies() + public virtual ImportListPageableRequestChain GetMovies() { - var pageableRequests = new NetImportPageableRequestChain(); + var pageableRequests = new ImportListPageableRequestChain(); pageableRequests.Add(GetMoviesRequests()); return pageableRequests; } - private IEnumerable GetMoviesRequests() + private IEnumerable GetMoviesRequests() { var minVoteCount = Settings.FilterCriteria.MinVotes; var minVoteAverage = Settings.FilterCriteria.MinVoteAverage; @@ -102,7 +102,7 @@ namespace NzbDrone.Core.NetImport.TMDb.Popular requestBuilder.AddQueryParam("page", pageNumber, true); - yield return new NetImportRequest(requestBuilder.Build()); + yield return new ImportListRequest(requestBuilder.Build()); } } } diff --git a/src/NzbDrone.Core/NetImport/TMDb/Popular/TMDbPopularSettings.cs b/src/NzbDrone.Core/ImportLists/TMDb/Popular/TMDbPopularSettings.cs similarity index 95% rename from src/NzbDrone.Core/NetImport/TMDb/Popular/TMDbPopularSettings.cs rename to src/NzbDrone.Core/ImportLists/TMDb/Popular/TMDbPopularSettings.cs index c12cad65f..74e84bcf6 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/Popular/TMDbPopularSettings.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/Popular/TMDbPopularSettings.cs @@ -1,7 +1,7 @@ using FluentValidation; using NzbDrone.Core.Annotations; -namespace NzbDrone.Core.NetImport.TMDb.Popular +namespace NzbDrone.Core.ImportLists.TMDb.Popular { public class TMDbPopularSettingsValidator : TMDbSettingsBaseValidator { diff --git a/src/NzbDrone.Core/NetImport/TMDb/TMDBResources.cs b/src/NzbDrone.Core/ImportLists/TMDb/TMDBResources.cs similarity index 98% rename from src/NzbDrone.Core/NetImport/TMDb/TMDBResources.cs rename to src/NzbDrone.Core/ImportLists/TMDb/TMDBResources.cs index 8cbf37427..10f1c9f25 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/TMDBResources.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/TMDBResources.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace NzbDrone.Core.NetImport.TMDb +namespace NzbDrone.Core.ImportLists.TMDb { public class MovieSearchResource { diff --git a/src/NzbDrone.Core/NetImport/TMDb/TMDbFilterSettings.cs b/src/NzbDrone.Core/ImportLists/TMDb/TMDbFilterSettings.cs similarity index 98% rename from src/NzbDrone.Core/NetImport/TMDb/TMDbFilterSettings.cs rename to src/NzbDrone.Core/ImportLists/TMDb/TMDbFilterSettings.cs index 50230fb5a..b881a0ba5 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/TMDbFilterSettings.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/TMDbFilterSettings.cs @@ -3,7 +3,7 @@ using FluentValidation; using NzbDrone.Common.Extensions; using NzbDrone.Core.Annotations; -namespace NzbDrone.Core.NetImport.TMDb +namespace NzbDrone.Core.ImportLists.TMDb { public class TMDbFilterSettingsValidator : AbstractValidator { diff --git a/src/NzbDrone.Core/NetImport/TMDb/TMDbImportBase.cs b/src/NzbDrone.Core/ImportLists/TMDb/TMDbImportBase.cs similarity index 63% rename from src/NzbDrone.Core/NetImport/TMDb/TMDbImportBase.cs rename to src/NzbDrone.Core/ImportLists/TMDb/TMDbImportBase.cs index b02dbf99e..3c4df1b7c 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/TMDbImportBase.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/TMDbImportBase.cs @@ -5,24 +5,24 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.MetadataSource; using NzbDrone.Core.Parser; -namespace NzbDrone.Core.NetImport.TMDb +namespace NzbDrone.Core.ImportLists.TMDb { - public abstract class TMDbNetImportBase : HttpNetImportBase + public abstract class TMDbImportListBase : HttpImportListBase where TSettings : TMDbSettingsBase, new() { - public override NetImportType ListType => NetImportType.TMDB; + public override ImportListType ListType => ImportListType.TMDB; public readonly ISearchForNewMovie _skyhookProxy; public readonly IHttpRequestBuilderFactory _requestBuilder; - protected TMDbNetImportBase(IRadarrCloudRequestBuilder requestBuilder, + protected TMDbImportListBase(IRadarrCloudRequestBuilder requestBuilder, IHttpClient httpClient, - INetImportStatusService netImportStatusService, + IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, ISearchForNewMovie skyhookProxy, Logger logger) - : base(httpClient, netImportStatusService, configService, parsingService, logger) + : base(httpClient, importListStatusService, configService, parsingService, logger) { _skyhookProxy = skyhookProxy; _requestBuilder = requestBuilder.TMDB; diff --git a/src/NzbDrone.Core/NetImport/TMDb/TMDbLanguageCodes.cs b/src/NzbDrone.Core/ImportLists/TMDb/TMDbLanguageCodes.cs similarity index 86% rename from src/NzbDrone.Core/NetImport/TMDb/TMDbLanguageCodes.cs rename to src/NzbDrone.Core/ImportLists/TMDb/TMDbLanguageCodes.cs index 29e8d0343..39c107e1e 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/TMDbLanguageCodes.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/TMDbLanguageCodes.cs @@ -1,4 +1,4 @@ -namespace NzbDrone.Core.NetImport.TMDb +namespace NzbDrone.Core.ImportLists.TMDb { public enum TMDbLanguageCodes { diff --git a/src/NzbDrone.Core/NetImport/TMDb/TMDbParser.cs b/src/NzbDrone.Core/ImportLists/TMDb/TMDbParser.cs similarity index 73% rename from src/NzbDrone.Core/NetImport/TMDb/TMDbParser.cs rename to src/NzbDrone.Core/ImportLists/TMDb/TMDbParser.cs index 2229da7d2..3164013db 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/TMDbParser.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/TMDbParser.cs @@ -3,17 +3,17 @@ using System.Collections.Generic; using System.Net; using Newtonsoft.Json; using NzbDrone.Common.Extensions; +using NzbDrone.Core.ImportLists.Exceptions; +using NzbDrone.Core.ImportLists.ImportListMovies; using NzbDrone.Core.MediaCover; -using NzbDrone.Core.Movies; -using NzbDrone.Core.NetImport.Exceptions; -namespace NzbDrone.Core.NetImport.TMDb +namespace NzbDrone.Core.ImportLists.TMDb { - public class TMDbParser : IParseNetImportResponse + public class TMDbParser : IParseImportListResponse { - public virtual IList ParseResponse(NetImportResponse importResponse) + public virtual IList ParseResponse(ImportListResponse importResponse) { - var movies = new List(); + var movies = new List(); if (!PreProcess(importResponse)) { @@ -31,15 +31,15 @@ namespace NzbDrone.Core.NetImport.TMDb return jsonResponse.Results.SelectList(MapListMovie); } - protected Movie MapListMovie(MovieResultResource movieResult) + protected ImportListMovie MapListMovie(MovieResultResource movieResult) { - var movie = new Movie + var movie = new ImportListMovie { TmdbId = movieResult.Id, Overview = movieResult.Overview, - Title = movieResult.OriginalTitle, - SortTitle = Parser.Parser.NormalizeTitle(movieResult.OriginalTitle), - Images = new List() + Title = movieResult.Title, + SortTitle = Parser.Parser.NormalizeTitle(movieResult.Title), + Images = new List(), }; if (movieResult.ReleaseDate.IsNotNullOrWhiteSpace()) @@ -63,11 +63,11 @@ namespace NzbDrone.Core.NetImport.TMDb return null; } - protected virtual bool PreProcess(NetImportResponse listResponse) + protected virtual bool PreProcess(ImportListResponse listResponse) { if (listResponse.HttpResponse.StatusCode != HttpStatusCode.OK) { - throw new NetImportException(listResponse, + throw new ImportListException(listResponse, "TMDb API call resulted in an unexpected StatusCode [{0}]", listResponse.HttpResponse.StatusCode); } @@ -77,7 +77,7 @@ namespace NzbDrone.Core.NetImport.TMDb listResponse.HttpRequest.Headers.Accept != null && !listResponse.HttpRequest.Headers.Accept.Contains("text/json")) { - throw new NetImportException(listResponse, + throw new ImportListException(listResponse, "TMDb responded with html content. Site is likely blocked or unavailable."); } diff --git a/src/NzbDrone.Core/NetImport/TMDb/TMDbSettings.cs b/src/NzbDrone.Core/ImportLists/TMDb/TMDbSettings.cs similarity index 94% rename from src/NzbDrone.Core/NetImport/TMDb/TMDbSettings.cs rename to src/NzbDrone.Core/ImportLists/TMDb/TMDbSettings.cs index 2236e6fa3..72b84eaf4 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/TMDbSettings.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/TMDbSettings.cs @@ -2,7 +2,7 @@ using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; -namespace NzbDrone.Core.NetImport.TMDb +namespace NzbDrone.Core.ImportLists.TMDb { public class TMDbSettingsBaseValidator : AbstractValidator where TSettings : TMDbSettingsBase diff --git a/src/NzbDrone.Core/NetImport/TMDb/User/TMDbUserImport.cs b/src/NzbDrone.Core/ImportLists/TMDb/User/TMDbUserImport.cs similarity index 87% rename from src/NzbDrone.Core/NetImport/TMDb/User/TMDbUserImport.cs rename to src/NzbDrone.Core/ImportLists/TMDb/User/TMDbUserImport.cs index 76156fce9..33a8c10c6 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/User/TMDbUserImport.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/User/TMDbUserImport.cs @@ -7,18 +7,18 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.MetadataSource; using NzbDrone.Core.Parser; -namespace NzbDrone.Core.NetImport.TMDb.User +namespace NzbDrone.Core.ImportLists.TMDb.User { - public class TMDbUserImport : TMDbNetImportBase + public class TMDbUserImport : TMDbImportListBase { public TMDbUserImport(IRadarrCloudRequestBuilder requestBuilder, IHttpClient httpClient, - INetImportStatusService netImportStatusService, + IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, ISearchForNewMovie searchForNewMovie, Logger logger) - : base(requestBuilder, httpClient, netImportStatusService, configService, parsingService, searchForNewMovie, logger) + : base(requestBuilder, httpClient, importListStatusService, configService, parsingService, searchForNewMovie, logger) { } @@ -26,12 +26,12 @@ namespace NzbDrone.Core.NetImport.TMDb.User public override bool Enabled => true; public override bool EnableAuto => false; - public override IParseNetImportResponse GetParser() + public override IParseImportListResponse GetParser() { return new TMDbParser(); } - public override INetImportRequestGenerator GetRequestGenerator() + public override IImportListRequestGenerator GetRequestGenerator() { return new TMDbUserRequestGenerator() { diff --git a/src/NzbDrone.Core/NetImport/TMDb/User/TMDbUserListType.cs b/src/NzbDrone.Core/ImportLists/TMDb/User/TMDbUserListType.cs similarity index 88% rename from src/NzbDrone.Core/NetImport/TMDb/User/TMDbUserListType.cs rename to src/NzbDrone.Core/ImportLists/TMDb/User/TMDbUserListType.cs index 07ee01cdb..0ddb0190e 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/User/TMDbUserListType.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/User/TMDbUserListType.cs @@ -1,6 +1,6 @@ using System.Runtime.Serialization; -namespace NzbDrone.Core.NetImport.TMDb.User +namespace NzbDrone.Core.ImportLists.TMDb.User { public enum TMDbUserListType { diff --git a/src/NzbDrone.Core/NetImport/TMDb/User/TMDbUserRequestGenerator.cs b/src/NzbDrone.Core/ImportLists/TMDb/User/TMDbUserRequestGenerator.cs similarity index 82% rename from src/NzbDrone.Core/NetImport/TMDb/User/TMDbUserRequestGenerator.cs rename to src/NzbDrone.Core/ImportLists/TMDb/User/TMDbUserRequestGenerator.cs index 10aaab253..48a5baeee 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/User/TMDbUserRequestGenerator.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/User/TMDbUserRequestGenerator.cs @@ -2,9 +2,9 @@ using NLog; using NzbDrone.Common.Http; -namespace NzbDrone.Core.NetImport.TMDb.User +namespace NzbDrone.Core.ImportLists.TMDb.User { - public class TMDbUserRequestGenerator : INetImportRequestGenerator + public class TMDbUserRequestGenerator : IImportListRequestGenerator { public TMDbUserSettings Settings { get; set; } public IHttpClient HttpClient { get; set; } @@ -18,16 +18,16 @@ namespace NzbDrone.Core.NetImport.TMDb.User MaxPages = 3; } - public virtual NetImportPageableRequestChain GetMovies() + public virtual ImportListPageableRequestChain GetMovies() { - var pageableRequests = new NetImportPageableRequestChain(); + var pageableRequests = new ImportListPageableRequestChain(); pageableRequests.Add(GetMoviesRequests()); return pageableRequests; } - private IEnumerable GetMoviesRequests() + private IEnumerable GetMoviesRequests() { var requestBuilder = RequestBuilder.Create() .SetHeader("Authorization", $"Bearer {Settings.AccessToken}") @@ -55,7 +55,7 @@ namespace NzbDrone.Core.NetImport.TMDb.User requestBuilder.Method = HttpMethod.GET; - yield return new NetImportRequest(requestBuilder.Build()); + yield return new ImportListRequest(requestBuilder.Build()); } } } diff --git a/src/NzbDrone.Core/NetImport/TMDb/User/TMDbUserSettings.cs b/src/NzbDrone.Core/ImportLists/TMDb/User/TMDbUserSettings.cs similarity index 96% rename from src/NzbDrone.Core/NetImport/TMDb/User/TMDbUserSettings.cs rename to src/NzbDrone.Core/ImportLists/TMDb/User/TMDbUserSettings.cs index 8e708e8f6..aa01754e5 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/User/TMDbUserSettings.cs +++ b/src/NzbDrone.Core/ImportLists/TMDb/User/TMDbUserSettings.cs @@ -1,7 +1,7 @@ using FluentValidation; using NzbDrone.Core.Annotations; -namespace NzbDrone.Core.NetImport.TMDb.User +namespace NzbDrone.Core.ImportLists.TMDb.User { public class TMDbUserSettingsValidator : TMDbSettingsBaseValidator { diff --git a/src/NzbDrone.Core/NetImport/Trakt/List/TraktListImport.cs b/src/NzbDrone.Core/ImportLists/Trakt/List/TraktListImport.cs similarity index 67% rename from src/NzbDrone.Core/NetImport/Trakt/List/TraktListImport.cs rename to src/NzbDrone.Core/ImportLists/Trakt/List/TraktListImport.cs index 958febba5..0691a35c6 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/List/TraktListImport.cs +++ b/src/NzbDrone.Core/ImportLists/Trakt/List/TraktListImport.cs @@ -4,18 +4,18 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.Notifications.Trakt; using NzbDrone.Core.Parser; -namespace NzbDrone.Core.NetImport.Trakt.List +namespace NzbDrone.Core.ImportLists.Trakt.List { public class TraktListImport : TraktImportBase { - public TraktListImport(INetImportRepository netImportRepository, + public TraktListImport(IImportListRepository importListRepository, ITraktProxy traktProxy, IHttpClient httpClient, - INetImportStatusService netImportStatusService, + IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, Logger logger) - : base(netImportRepository, traktProxy, httpClient, netImportStatusService, configService, parsingService, logger) + : base(importListRepository, traktProxy, httpClient, importListStatusService, configService, parsingService, logger) { } @@ -23,7 +23,7 @@ namespace NzbDrone.Core.NetImport.Trakt.List public override bool Enabled => true; public override bool EnableAuto => false; - public override INetImportRequestGenerator GetRequestGenerator() + public override IImportListRequestGenerator GetRequestGenerator() { return new TraktListRequestGenerator(_traktProxy) { diff --git a/src/NzbDrone.Core/NetImport/Trakt/List/TraktListRequestGenerator.cs b/src/NzbDrone.Core/ImportLists/Trakt/List/TraktListRequestGenerator.cs similarity index 62% rename from src/NzbDrone.Core/NetImport/Trakt/List/TraktListRequestGenerator.cs rename to src/NzbDrone.Core/ImportLists/Trakt/List/TraktListRequestGenerator.cs index b5d8a94cb..3be121a9f 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/List/TraktListRequestGenerator.cs +++ b/src/NzbDrone.Core/ImportLists/Trakt/List/TraktListRequestGenerator.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using NzbDrone.Common.Http; using NzbDrone.Core.Notifications.Trakt; -namespace NzbDrone.Core.NetImport.Trakt.List +namespace NzbDrone.Core.ImportLists.Trakt.List { - public class TraktListRequestGenerator : INetImportRequestGenerator + public class TraktListRequestGenerator : IImportListRequestGenerator { private readonly ITraktProxy _traktProxy; public TraktListSettings Settings { get; set; } @@ -14,23 +14,23 @@ namespace NzbDrone.Core.NetImport.Trakt.List _traktProxy = traktProxy; } - public virtual NetImportPageableRequestChain GetMovies() + public virtual ImportListPageableRequestChain GetMovies() { - var pageableRequests = new NetImportPageableRequestChain(); + var pageableRequests = new ImportListPageableRequestChain(); pageableRequests.Add(GetMoviesRequest()); return pageableRequests; } - private IEnumerable GetMoviesRequest() + private IEnumerable GetMoviesRequest() { var link = string.Empty; var listName = Parser.Parser.ToUrlSlug(Settings.Listname.Trim()); link += $"users/{Settings.Username.Trim()}/lists/{listName}/items/movies?limit={Settings.Limit}"; - var request = new NetImportRequest(_traktProxy.BuildTraktRequest(link, HttpMethod.GET, Settings.AccessToken)); + var request = new ImportListRequest(_traktProxy.BuildTraktRequest(link, HttpMethod.GET, Settings.AccessToken)); yield return request; } diff --git a/src/NzbDrone.Core/NetImport/Trakt/List/TraktListSettings.cs b/src/NzbDrone.Core/ImportLists/Trakt/List/TraktListSettings.cs similarity index 94% rename from src/NzbDrone.Core/NetImport/Trakt/List/TraktListSettings.cs rename to src/NzbDrone.Core/ImportLists/Trakt/List/TraktListSettings.cs index f6f560910..194c27a79 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/List/TraktListSettings.cs +++ b/src/NzbDrone.Core/ImportLists/Trakt/List/TraktListSettings.cs @@ -1,7 +1,7 @@ using FluentValidation; using NzbDrone.Core.Annotations; -namespace NzbDrone.Core.NetImport.Trakt.List +namespace NzbDrone.Core.ImportLists.Trakt.List { public class TraktListSettingsValidator : TraktSettingsBaseValidator { diff --git a/src/NzbDrone.Core/NetImport/Trakt/Popular/TraktPopularImport.cs b/src/NzbDrone.Core/ImportLists/Trakt/Popular/TraktPopularImport.cs similarity index 66% rename from src/NzbDrone.Core/NetImport/Trakt/Popular/TraktPopularImport.cs rename to src/NzbDrone.Core/ImportLists/Trakt/Popular/TraktPopularImport.cs index b552ee374..1739d1853 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/Popular/TraktPopularImport.cs +++ b/src/NzbDrone.Core/ImportLists/Trakt/Popular/TraktPopularImport.cs @@ -4,18 +4,18 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.Notifications.Trakt; using NzbDrone.Core.Parser; -namespace NzbDrone.Core.NetImport.Trakt.Popular +namespace NzbDrone.Core.ImportLists.Trakt.Popular { public class TraktPopularImport : TraktImportBase { - public TraktPopularImport(INetImportRepository netImportRepository, + public TraktPopularImport(IImportListRepository importListRepository, ITraktProxy traktProxy, IHttpClient httpClient, - INetImportStatusService netImportStatusService, + IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, Logger logger) - : base(netImportRepository, traktProxy, httpClient, netImportStatusService, configService, parsingService, logger) + : base(importListRepository, traktProxy, httpClient, importListStatusService, configService, parsingService, logger) { } @@ -23,12 +23,12 @@ namespace NzbDrone.Core.NetImport.Trakt.Popular public override bool Enabled => true; public override bool EnableAuto => false; - public override IParseNetImportResponse GetParser() + public override IParseImportListResponse GetParser() { return new TraktPopularParser(Settings); } - public override INetImportRequestGenerator GetRequestGenerator() + public override IImportListRequestGenerator GetRequestGenerator() { return new TraktPopularRequestGenerator(_traktProxy) { diff --git a/src/NzbDrone.Core/NetImport/Trakt/Popular/TraktPopularListType.cs b/src/NzbDrone.Core/ImportLists/Trakt/Popular/TraktPopularListType.cs similarity index 93% rename from src/NzbDrone.Core/NetImport/Trakt/Popular/TraktPopularListType.cs rename to src/NzbDrone.Core/ImportLists/Trakt/Popular/TraktPopularListType.cs index d380952a1..f45c1f848 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/Popular/TraktPopularListType.cs +++ b/src/NzbDrone.Core/ImportLists/Trakt/Popular/TraktPopularListType.cs @@ -1,6 +1,6 @@ using System.Runtime.Serialization; -namespace NzbDrone.Core.NetImport.Trakt.Popular +namespace NzbDrone.Core.ImportLists.Trakt.Popular { public enum TraktPopularListType { diff --git a/src/NzbDrone.Core/NetImport/Trakt/Popular/TraktPopularParser.cs b/src/NzbDrone.Core/ImportLists/Trakt/Popular/TraktPopularParser.cs similarity index 80% rename from src/NzbDrone.Core/NetImport/Trakt/Popular/TraktPopularParser.cs rename to src/NzbDrone.Core/ImportLists/Trakt/Popular/TraktPopularParser.cs index da563f26d..ee9bfed77 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/Popular/TraktPopularParser.cs +++ b/src/NzbDrone.Core/ImportLists/Trakt/Popular/TraktPopularParser.cs @@ -1,26 +1,26 @@ using System.Collections.Generic; using Newtonsoft.Json; using NzbDrone.Common.Extensions; -using NzbDrone.Core.Movies; +using NzbDrone.Core.ImportLists.ImportListMovies; using NzbDrone.Core.Notifications.Trakt.Resource; -namespace NzbDrone.Core.NetImport.Trakt.Popular +namespace NzbDrone.Core.ImportLists.Trakt.Popular { public class TraktPopularParser : TraktParser { private readonly TraktPopularSettings _settings; - private NetImportResponse _importResponse; + private ImportListResponse _importResponse; public TraktPopularParser(TraktPopularSettings settings) { _settings = settings; } - public override IList ParseResponse(NetImportResponse importResponse) + public override IList ParseResponse(ImportListResponse importResponse) { _importResponse = importResponse; - var movies = new List(); + var movies = new List(); if (!PreProcess(_importResponse)) { @@ -46,7 +46,7 @@ namespace NzbDrone.Core.NetImport.Trakt.Popular foreach (var movie in jsonResponse) { - movies.AddIfNotNull(new Movies.Movie() + movies.AddIfNotNull(new ImportListMovie() { Title = movie.Title, ImdbId = movie.Ids.Imdb, diff --git a/src/NzbDrone.Core/NetImport/Trakt/Popular/TraktPopularRequestGenerator.cs b/src/NzbDrone.Core/ImportLists/Trakt/Popular/TraktPopularRequestGenerator.cs similarity index 82% rename from src/NzbDrone.Core/NetImport/Trakt/Popular/TraktPopularRequestGenerator.cs rename to src/NzbDrone.Core/ImportLists/Trakt/Popular/TraktPopularRequestGenerator.cs index aa10daee9..172248c02 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/Popular/TraktPopularRequestGenerator.cs +++ b/src/NzbDrone.Core/ImportLists/Trakt/Popular/TraktPopularRequestGenerator.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using NzbDrone.Common.Http; using NzbDrone.Core.Notifications.Trakt; -namespace NzbDrone.Core.NetImport.Trakt.Popular +namespace NzbDrone.Core.ImportLists.Trakt.Popular { - public class TraktPopularRequestGenerator : INetImportRequestGenerator + public class TraktPopularRequestGenerator : IImportListRequestGenerator { private readonly ITraktProxy _traktProxy; public TraktPopularSettings Settings { get; set; } @@ -14,16 +14,16 @@ namespace NzbDrone.Core.NetImport.Trakt.Popular _traktProxy = traktProxy; } - public virtual NetImportPageableRequestChain GetMovies() + public virtual ImportListPageableRequestChain GetMovies() { - var pageableRequests = new NetImportPageableRequestChain(); + var pageableRequests = new ImportListPageableRequestChain(); pageableRequests.Add(GetMoviesRequest()); return pageableRequests; } - private IEnumerable GetMoviesRequest() + private IEnumerable GetMoviesRequest() { var link = string.Empty; @@ -57,7 +57,7 @@ namespace NzbDrone.Core.NetImport.Trakt.Popular break; } - var request = new NetImportRequest(_traktProxy.BuildTraktRequest(link, HttpMethod.GET, Settings.AccessToken)); + var request = new ImportListRequest(_traktProxy.BuildTraktRequest(link, HttpMethod.GET, Settings.AccessToken)); yield return request; } diff --git a/src/NzbDrone.Core/NetImport/Trakt/Popular/TraktPopularSettings.cs b/src/NzbDrone.Core/ImportLists/Trakt/Popular/TraktPopularSettings.cs similarity index 94% rename from src/NzbDrone.Core/NetImport/Trakt/Popular/TraktPopularSettings.cs rename to src/NzbDrone.Core/ImportLists/Trakt/Popular/TraktPopularSettings.cs index 39ba6d502..60c0fa8e7 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/Popular/TraktPopularSettings.cs +++ b/src/NzbDrone.Core/ImportLists/Trakt/Popular/TraktPopularSettings.cs @@ -1,7 +1,7 @@ using FluentValidation; using NzbDrone.Core.Annotations; -namespace NzbDrone.Core.NetImport.Trakt.Popular +namespace NzbDrone.Core.ImportLists.Trakt.Popular { public class TraktPopularSettingsValidator : TraktSettingsBaseValidator { diff --git a/src/NzbDrone.Core/NetImport/Trakt/TraktImportBase.cs b/src/NzbDrone.Core/ImportLists/Trakt/TraktImportBase.cs similarity index 70% rename from src/NzbDrone.Core/NetImport/Trakt/TraktImportBase.cs rename to src/NzbDrone.Core/ImportLists/Trakt/TraktImportBase.cs index 77f27f79d..330aab737 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/TraktImportBase.cs +++ b/src/NzbDrone.Core/ImportLists/Trakt/TraktImportBase.cs @@ -7,29 +7,29 @@ using NzbDrone.Core.Notifications.Trakt; using NzbDrone.Core.Parser; using NzbDrone.Core.Validation; -namespace NzbDrone.Core.NetImport.Trakt +namespace NzbDrone.Core.ImportLists.Trakt { - public abstract class TraktImportBase : HttpNetImportBase + public abstract class TraktImportBase : HttpImportListBase where TSettings : TraktSettingsBase, new() { public ITraktProxy _traktProxy; - private readonly INetImportRepository _netImportRepository; - public override NetImportType ListType => NetImportType.Trakt; + private readonly IImportListRepository _importListRepository; + public override ImportListType ListType => ImportListType.Trakt; - protected TraktImportBase(INetImportRepository netImportRepository, - ITraktProxy traktProxy, - IHttpClient httpClient, - INetImportStatusService netImportStatusService, - IConfigService configService, - IParsingService parsingService, - Logger logger) - : base(httpClient, netImportStatusService, configService, parsingService, logger) + protected TraktImportBase(IImportListRepository importListRepository, + ITraktProxy traktProxy, + IHttpClient httpClient, + IImportListStatusService importListStatusService, + IConfigService configService, + IParsingService parsingService, + Logger logger) + : base(httpClient, importListStatusService, configService, parsingService, logger) { - _netImportRepository = netImportRepository; + _importListRepository = importListRepository; _traktProxy = traktProxy; } - public override NetImportFetchResult Fetch() + public override ImportListFetchResult Fetch() { Settings.Validate().Filter("AccessToken", "RefreshToken").ThrowOnError(); _logger.Trace($"Access token expires at {Settings.Expires}"); @@ -43,7 +43,7 @@ namespace NzbDrone.Core.NetImport.Trakt return FetchMovies(generator.GetMovies()); } - public override IParseNetImportResponse GetParser() + public override IParseImportListResponse GetParser() { return new TraktParser(); } @@ -92,7 +92,7 @@ namespace NzbDrone.Core.NetImport.Trakt if (Definition.Id > 0) { - _netImportRepository.UpdateSettings((NetImportDefinition)Definition); + _importListRepository.UpdateSettings((ImportListDefinition)Definition); } } } diff --git a/src/NzbDrone.Core/ImportLists/Trakt/TraktParser.cs b/src/NzbDrone.Core/ImportLists/Trakt/TraktParser.cs new file mode 100644 index 000000000..614430f07 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/Trakt/TraktParser.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using System.Net; +using Newtonsoft.Json; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.ImportLists.Exceptions; +using NzbDrone.Core.ImportLists.ImportListMovies; +using NzbDrone.Core.Notifications.Trakt.Resource; + +namespace NzbDrone.Core.ImportLists.Trakt +{ + public class TraktParser : IParseImportListResponse + { + private ImportListResponse _importResponse; + + public TraktParser() + { + } + + public virtual IList ParseResponse(ImportListResponse importResponse) + { + _importResponse = importResponse; + + var movies = new List(); + + if (!PreProcess(_importResponse)) + { + return movies; + } + + var jsonResponse = JsonConvert.DeserializeObject>(_importResponse.Content); + + // no movies were return + if (jsonResponse == null) + { + return movies; + } + + foreach (var movie in jsonResponse) + { + movies.AddIfNotNull(new ImportListMovie() + { + Title = movie.Movie.Title, + ImdbId = movie.Movie.Ids.Imdb, + TmdbId = movie.Movie.Ids.Tmdb, + Year = movie.Movie.Year ?? 0 + }); + } + + return movies; + } + + protected virtual bool PreProcess(ImportListResponse importListResponse) + { + if (importListResponse.HttpResponse.StatusCode != HttpStatusCode.OK) + { + throw new ImportListException(importListResponse, "Trakt API call resulted in an unexpected StatusCode [{0}]", importListResponse.HttpResponse.StatusCode); + } + + if (importListResponse.HttpResponse.Headers.ContentType != null && importListResponse.HttpResponse.Headers.ContentType.Contains("text/json") && + importListResponse.HttpRequest.Headers.Accept != null && !importListResponse.HttpRequest.Headers.Accept.Contains("text/json")) + { + throw new ImportListException(importListResponse, "Trakt API responded with html content. Site is likely blocked or unavailable."); + } + + return true; + } + } +} diff --git a/src/NzbDrone.Core/NetImport/Trakt/TraktSettingsBase.cs b/src/NzbDrone.Core/ImportLists/Trakt/TraktSettingsBase.cs similarity index 98% rename from src/NzbDrone.Core/NetImport/Trakt/TraktSettingsBase.cs rename to src/NzbDrone.Core/ImportLists/Trakt/TraktSettingsBase.cs index 6a1b60a5c..b5dbf6407 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/TraktSettingsBase.cs +++ b/src/NzbDrone.Core/ImportLists/Trakt/TraktSettingsBase.cs @@ -6,7 +6,7 @@ using NzbDrone.Core.Annotations; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; -namespace NzbDrone.Core.NetImport.Trakt +namespace NzbDrone.Core.ImportLists.Trakt { public class TraktSettingsBaseValidator : AbstractValidator where TSettings : TraktSettingsBase diff --git a/src/NzbDrone.Core/NetImport/Trakt/User/TraktUserImport.cs b/src/NzbDrone.Core/ImportLists/Trakt/User/TraktUserImport.cs similarity index 67% rename from src/NzbDrone.Core/NetImport/Trakt/User/TraktUserImport.cs rename to src/NzbDrone.Core/ImportLists/Trakt/User/TraktUserImport.cs index 608aebc3c..6f8198cd7 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/User/TraktUserImport.cs +++ b/src/NzbDrone.Core/ImportLists/Trakt/User/TraktUserImport.cs @@ -4,18 +4,18 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.Notifications.Trakt; using NzbDrone.Core.Parser; -namespace NzbDrone.Core.NetImport.Trakt.User +namespace NzbDrone.Core.ImportLists.Trakt.User { public class TraktUserImport : TraktImportBase { - public TraktUserImport(INetImportRepository netImportRepository, + public TraktUserImport(IImportListRepository importListRepository, ITraktProxy traktProxy, IHttpClient httpClient, - INetImportStatusService netImportStatusService, + IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, Logger logger) - : base(netImportRepository, traktProxy, httpClient, netImportStatusService, configService, parsingService, logger) + : base(importListRepository, traktProxy, httpClient, importListStatusService, configService, parsingService, logger) { } @@ -23,7 +23,7 @@ namespace NzbDrone.Core.NetImport.Trakt.User public override bool Enabled => true; public override bool EnableAuto => false; - public override INetImportRequestGenerator GetRequestGenerator() + public override IImportListRequestGenerator GetRequestGenerator() { return new TraktUserRequestGenerator(_traktProxy) { diff --git a/src/NzbDrone.Core/NetImport/Trakt/User/TraktUserListType.cs b/src/NzbDrone.Core/ImportLists/Trakt/User/TraktUserListType.cs similarity index 87% rename from src/NzbDrone.Core/NetImport/Trakt/User/TraktUserListType.cs rename to src/NzbDrone.Core/ImportLists/Trakt/User/TraktUserListType.cs index 24c147fa2..b90508d14 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/User/TraktUserListType.cs +++ b/src/NzbDrone.Core/ImportLists/Trakt/User/TraktUserListType.cs @@ -1,6 +1,6 @@ using System.Runtime.Serialization; -namespace NzbDrone.Core.NetImport.Trakt.User +namespace NzbDrone.Core.ImportLists.Trakt.User { public enum TraktUserListType { diff --git a/src/NzbDrone.Core/NetImport/Trakt/User/TraktUserRequestGenerator.cs b/src/NzbDrone.Core/ImportLists/Trakt/User/TraktUserRequestGenerator.cs similarity index 72% rename from src/NzbDrone.Core/NetImport/Trakt/User/TraktUserRequestGenerator.cs rename to src/NzbDrone.Core/ImportLists/Trakt/User/TraktUserRequestGenerator.cs index e3d664788..41ac99a1a 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/User/TraktUserRequestGenerator.cs +++ b/src/NzbDrone.Core/ImportLists/Trakt/User/TraktUserRequestGenerator.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using NzbDrone.Common.Http; using NzbDrone.Core.Notifications.Trakt; -namespace NzbDrone.Core.NetImport.Trakt.User +namespace NzbDrone.Core.ImportLists.Trakt.User { - public class TraktUserRequestGenerator : INetImportRequestGenerator + public class TraktUserRequestGenerator : IImportListRequestGenerator { private readonly ITraktProxy _traktProxy; public TraktUserSettings Settings { get; set; } @@ -14,16 +14,16 @@ namespace NzbDrone.Core.NetImport.Trakt.User _traktProxy = traktProxy; } - public virtual NetImportPageableRequestChain GetMovies() + public virtual ImportListPageableRequestChain GetMovies() { - var pageableRequests = new NetImportPageableRequestChain(); + var pageableRequests = new ImportListPageableRequestChain(); pageableRequests.Add(GetMoviesRequest()); return pageableRequests; } - private IEnumerable GetMoviesRequest() + private IEnumerable GetMoviesRequest() { var link = string.Empty; @@ -40,7 +40,7 @@ namespace NzbDrone.Core.NetImport.Trakt.User break; } - var request = new NetImportRequest(_traktProxy.BuildTraktRequest(link, HttpMethod.GET, Settings.AccessToken)); + var request = new ImportListRequest(_traktProxy.BuildTraktRequest(link, HttpMethod.GET, Settings.AccessToken)); yield return request; } diff --git a/src/NzbDrone.Core/NetImport/Trakt/User/TraktUserSettings.cs b/src/NzbDrone.Core/ImportLists/Trakt/User/TraktUserSettings.cs similarity index 94% rename from src/NzbDrone.Core/NetImport/Trakt/User/TraktUserSettings.cs rename to src/NzbDrone.Core/ImportLists/Trakt/User/TraktUserSettings.cs index a487db0c8..da8a74557 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/User/TraktUserSettings.cs +++ b/src/NzbDrone.Core/ImportLists/Trakt/User/TraktUserSettings.cs @@ -1,7 +1,7 @@ using FluentValidation; using NzbDrone.Core.Annotations; -namespace NzbDrone.Core.NetImport.Trakt.User +namespace NzbDrone.Core.ImportLists.Trakt.User { public class TraktUserSettingsValidator : TraktSettingsBaseValidator { diff --git a/src/NzbDrone.Core/Jobs/TaskManager.cs b/src/NzbDrone.Core/Jobs/TaskManager.cs index 6b9f9f9c1..2f7d61bb6 100644 --- a/src/NzbDrone.Core/Jobs/TaskManager.cs +++ b/src/NzbDrone.Core/Jobs/TaskManager.cs @@ -8,13 +8,13 @@ using NzbDrone.Core.Configuration.Events; using NzbDrone.Core.Download; using NzbDrone.Core.HealthCheck; using NzbDrone.Core.Housekeeping; +using NzbDrone.Core.ImportLists; using NzbDrone.Core.Indexers; using NzbDrone.Core.Lifecycle; using NzbDrone.Core.MediaFiles.Commands; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Movies.Commands; -using NzbDrone.Core.NetImport; using NzbDrone.Core.Update.Commands; namespace NzbDrone.Core.Jobs @@ -93,8 +93,8 @@ namespace NzbDrone.Core.Jobs new ScheduledTask { - Interval = GetNetImportSyncInterval(), - TypeName = typeof(NetImportSyncCommand).FullName + Interval = GetImportListSyncInterval(), + TypeName = typeof(ImportListSyncCommand).FullName }, new ScheduledTask @@ -156,9 +156,9 @@ namespace NzbDrone.Core.Jobs return interval; } - private int GetNetImportSyncInterval() + private int GetImportListSyncInterval() { - var interval = _configService.NetImportSyncInterval; + var interval = _configService.ImportListSyncInterval; if (interval > 0 && interval < 10) { @@ -189,13 +189,13 @@ namespace NzbDrone.Core.Jobs var rss = _scheduledTaskRepository.GetDefinition(typeof(RssSyncCommand)); rss.Interval = _configService.RssSyncInterval; - var netImport = _scheduledTaskRepository.GetDefinition(typeof(NetImportSyncCommand)); - netImport.Interval = _configService.NetImportSyncInterval; + var importList = _scheduledTaskRepository.GetDefinition(typeof(ImportListSyncCommand)); + importList.Interval = _configService.ImportListSyncInterval; var refreshMonitoredDownloads = _scheduledTaskRepository.GetDefinition(typeof(RefreshMonitoredDownloadsCommand)); refreshMonitoredDownloads.Interval = _configService.CheckForFinishedDownloadInterval; - _scheduledTaskRepository.UpdateMany(new List { rss, netImport, refreshMonitoredDownloads }); + _scheduledTaskRepository.UpdateMany(new List { rss, importList, refreshMonitoredDownloads }); } } } diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index ecac8c017..0b639fb15 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -94,8 +94,8 @@ "MovieIndex": "Filmindex", "MovieNaming": "Filmbenennung", "Movies": "Filme", - "NetImportStatusCheckAllClientMessage": "Alle Listen sind aufgrund von Fehlern nicht verfügbar", - "NetImportStatusCheckSingleClientMessage": "Listen aufgrund von Fehlern nicht verfügbar: {0}", + "ImportListStatusCheckAllClientMessage": "Alle Listen sind aufgrund von Fehlern nicht verfügbar", + "ImportListStatusCheckSingleClientMessage": "Listen aufgrund von Fehlern nicht verfügbar: {0}", "NoChange": "Keine Änderung", "NoChanges": "Keine Änderungen", "Options": "Optionen", @@ -327,7 +327,7 @@ "UsenetDelayHelpText": "Verzögerung in Minuten before ein Usenet-Release erfasst wird", "WhitelistedHardcodedSubsHelpText": "Hier gesetzte Untertitel Tags werden nciht als hartcodiert erachtet", "EnableAutoHelpText": "Wenn aktiviert werden Filme dieser Liste automatisch hinzugefügt", - "AddNetImportExclusionHelpText": "Automatisches ( wieder- ) hinzufügen durch Listen verhindern", + "AddImportExclusionHelpText": "Automatisches ( wieder- ) hinzufügen durch Listen verhindern", "AgeWhenGrabbed": "Alter (beim erfassen)", "AllowHardcodedSubs": "Hartcodierte Untertitel erlauben", "AlreadyInYourLibrary": "Bereits in deiner Bibliothek", @@ -595,10 +595,10 @@ "WhitelistedSubtitleTags": "Erlaubte Untertitel Tags", "YesCancel": "Ja, abbrechen", "EnableColorImpairedModeHelpText": "Alternativer Style, um farbbeeinträchtigten Benutzern eine bessere Unterscheidung farbcodierter Informationen zu ermöglichen", - "MovieIsOnNetImportExclusionList": "Film ist auf der Net Import Ausschluss Liste", + "MovieIsOnImportExclusionList": "Film ist auf der Net Import Ausschluss Liste", "RemoveHelpTextWarning": "Dies wird den Download und alle bereits heruntergeladenen Dateien aus dem Downloader entfernen.", "EnableMediaInfoHelpText": "Videoinformationen wie Auflösung, Laufzeit und Codec aus Datien erkennen. Dazu ist es erforderlich, dass Radarr Teile der Datei liest, was zu hoher Festplatten- oder Netzwerkaktivität während der Scans führen kann.", - "NetImportSyncIntervalHelpText": "Wie oft die Listen synchronisiert werden sollen.", + "ImportListSyncIntervalHelpText": "Wie oft die Listen synchronisiert werden sollen.", "AddListExclusion": "Listenausschluss hinzufügen", "AddMoviesMonitored": "Filme beobachtet hinzufügen", "HelpText": "Intervall in Minuten. Zum deaktivieren auf 0 setzen ( Dies wird das automatische Release erfassen deaktivieren )", diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 952f10764..c3c8a5a2d 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -8,7 +8,7 @@ "AddListExclusion": "Add List Exclusion", "AddMovies": "Add Movies", "AddMoviesMonitored": "Add Movies Monitored", - "AddNetImportExclusionHelpText": "Prevent movie from being added to Radarr by lists", + "AddImportExclusionHelpText": "Prevent movie from being added to Radarr by lists", "AddNew": "Add New", "AddNewMessage": "It's easy to add a new movie, just start typing the name of the movie you want to add", "AddNewMovie": "Add New Movie", @@ -332,7 +332,7 @@ "MovieIndex": "Movie Index", "MovieInfoLanguageHelpTextWarning": "Browser Reload Required", "MovieIsDownloading": "Movie is downloading", - "MovieIsOnNetImportExclusionList": "Movie is on Net Import Exclusion List", + "MovieIsOnImportExclusionList": "Movie is on Import Exclusion List", "MovieNaming": "Movie Naming", "Movies": "Movies", "MovieTitle": "Movie Title", @@ -344,10 +344,10 @@ "Name": "Name", "NamingSettings": "Naming Settings", "NetCore": ".NET Core", - "NetImportStatusCheckAllClientMessage": "All lists are unavailable due to failures", - "NetImportStatusCheckSingleClientMessage": "Lists unavailable due to failures: {0}", - "NetImportSyncIntervalHelpText": "How often Radarr syncs with your lists.", + "ImportListSyncIntervalHelpText": "How often Radarr syncs with your lists.", "New": "New", + "ImportListStatusCheckAllClientMessage": "All lists are unavailable due to failures", + "ImportListStatusCheckSingleClientMessage": "Lists unavailable due to failures: {0}", "NoChange": "No Change", "NoChanges": "No Changes", "NoLeaveIt": "No, Leave It", diff --git a/src/NzbDrone.Core/Localization/Core/es.json b/src/NzbDrone.Core/Localization/Core/es.json index 445ed225d..86878fa97 100644 --- a/src/NzbDrone.Core/Localization/Core/es.json +++ b/src/NzbDrone.Core/Localization/Core/es.json @@ -130,8 +130,8 @@ "Options": "Opciones", "NoChange": "Sin Cambio", "NoChanges": "Sin Cambios", - "NetImportStatusCheckSingleClientMessage": "Listas no disponibles debido a errores: {0}", - "NetImportStatusCheckAllClientMessage": "Las listas no están disponibles debido a errores", + "ImportListStatusCheckSingleClientMessage": "Listas no disponibles debido a errores: {0}", + "ImportListStatusCheckAllClientMessage": "Las listas no están disponibles debido a errores", "Movies": "Películas", "MovieNaming": "Renombrar Películas", "MonoNotNetCoreCheckMessage": "Por favor actualiza a la versión .NET Core de Radarr", @@ -417,7 +417,7 @@ "AllowHardcodedSubsHelpText": "Hardcoded subs que sean detectados serán automáticamente descargados", "AllowHardcodedSubs": "Permitir Hardcoded Subs", "AgeWhenGrabbed": "Edad (cuando capturada)", - "AddNetImportExclusionHelpText": "Prevenir que la película sea añadida a Radarr mediante listas", + "AddImportExclusionHelpText": "Prevenir que la película sea añadida a Radarr mediante listas", "AddMoviesMonitored": "Añadir Películas Monitoreadas", "AddListExclusion": "Añadir Exclusión De Lista" } diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index 2ac948dfe..3129f713d 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -135,8 +135,8 @@ "Options": "Options", "NoChanges": "Aucun changement", "NoChange": "Pas de changement", - "NetImportStatusCheckSingleClientMessage": "Listes indisponibles en raison d'échecs : {0}", - "NetImportStatusCheckAllClientMessage": "Toutes les listes ne sont pas disponibles en raison d'échecs", + "ImportListStatusCheckSingleClientMessage": "Listes indisponibles en raison d'échecs : {0}", + "ImportListStatusCheckAllClientMessage": "Toutes les listes ne sont pas disponibles en raison d'échecs", "MovieTitle": "Titre du film", "Movies": "Films", "MovieNaming": "Nommage des films", diff --git a/src/NzbDrone.Core/Localization/Core/it.json b/src/NzbDrone.Core/Localization/Core/it.json index 4d0c08981..9265a78d6 100644 --- a/src/NzbDrone.Core/Localization/Core/it.json +++ b/src/NzbDrone.Core/Localization/Core/it.json @@ -111,8 +111,8 @@ "Profiles": "Profili", "PreviewRename": "Anteprima Ridenominazione", "Options": "Opzioni", - "NetImportStatusCheckSingleClientMessage": "Liste non disponibili a causa di errori: {0}", - "NetImportStatusCheckAllClientMessage": "Tutte le liste non sono disponibili a causa di errori", + "ImportListStatusCheckSingleClientMessage": "Liste non disponibili a causa di errori: {0}", + "ImportListStatusCheckAllClientMessage": "Tutte le liste non sono disponibili a causa di errori", "MovieTitle": "Titolo Film", "Movies": "Film", "MovieIndex": "Indice Film", diff --git a/src/NzbDrone.Core/Localization/Core/nl.json b/src/NzbDrone.Core/Localization/Core/nl.json index 93a73c2be..c43dcb06c 100644 --- a/src/NzbDrone.Core/Localization/Core/nl.json +++ b/src/NzbDrone.Core/Localization/Core/nl.json @@ -107,8 +107,8 @@ "Options": "Opties", "NoChanges": "Geen Wijzigingen", "NoChange": "Geen Wijziging", - "NetImportStatusCheckSingleClientMessage": "Lijsten onbeschikbaar wegens fouten: {0}", - "NetImportStatusCheckAllClientMessage": "Alle lijsten zijn onbeschikbaar wegens fouten", + "ImportListStatusCheckSingleClientMessage": "Lijsten onbeschikbaar wegens fouten: {0}", + "ImportListStatusCheckAllClientMessage": "Alle lijsten zijn onbeschikbaar wegens fouten", "Movies": "Films", "MovieNaming": "Naamgeving", "MovieIndex": "Film Overzicht", @@ -331,7 +331,7 @@ "Authentication": "Authenticatie", "AreYouSureYouWantToDeleteThisDelayProfile": "Weet u zeker dat u dit vertragings profiel wilt verwijderen?", "AppDataDirectory": "AppData folder", - "AddNetImportExclusionHelpText": "Voorkom dat een film wordt toegevoegd door een lijst", + "AddImportExclusionHelpText": "Voorkom dat een film wordt toegevoegd door een lijst", "AgeWhenGrabbed": "Leeftijd (wanneer opgehaald)", "AnalyticsEnabledHelpText": "Stuur anonieme gebruiks- en foutinformatie naar de servers van Radarr. Dit omvat informatie over uw browser, welke Radarr WebUI pagina's u gebruikt, foutrapportage en OS en runtime versie. We zullen deze informatie gebruiken om prioriteiten te stellen voor functies en het verhelpen van fouten.", "AllowHardcodedSubsHelpText": "Gedetecteerde hardcoded subs worden automatisch gedownload", @@ -538,10 +538,10 @@ "MIA": "MIA", "MinFormatScoreHelpText": "Minimum score voor het toelaten van downloads voor eigen formaten", "MinimumFreeSpaceWhenImportingHelpText": "Voorkom import als het je met minder dat deze hoeveelheid aan schijfruimte over laat", - "MovieIsOnNetImportExclusionList": "Film staat op de uitsluitingslijst voor Net Import", + "MovieIsOnImportExclusionList": "Film staat op de uitsluitingslijst voor Net Import", "MovieTitleHelpText": "De titel van de uit te sluiten film (kan van alles zijn)", "MovieYearHelpText": "Het jaar van de uit te sluiten film", - "NetImportSyncIntervalHelpText": "Hoe vaak Radarr je lijsten synchroniseert.", + "ImportListSyncIntervalHelpText": "Hoe vaak Radarr je lijsten synchroniseert.", "NotificationTriggers": "Melding triggers", "OnDownloadHelpText": "Word op de hoogte gebracht wanneer films succesvol geïmporteerd zijn", "OnUpgradeHelpText": "Word op de hoogte gebracht wanneer films worden geüpgraded naar een betere kwaliteit", diff --git a/src/NzbDrone.Core/Localization/Core/ro.json b/src/NzbDrone.Core/Localization/Core/ro.json index 9edb9f753..900056cd5 100644 --- a/src/NzbDrone.Core/Localization/Core/ro.json +++ b/src/NzbDrone.Core/Localization/Core/ro.json @@ -112,8 +112,8 @@ "OAuthPopupMessage": "Browser-ul tău blochează pop-upurile", "NoChanges": "Nicio Modificare", "NoChange": "Nicio Modificare", - "NetImportStatusCheckSingleClientMessage": "Liste indisponibile datorită erorilor: {0}", - "NetImportStatusCheckAllClientMessage": "Toate listele sunt indisponibile datorită erorilor", + "ImportListStatusCheckSingleClientMessage": "Liste indisponibile datorită erorilor: {0}", + "ImportListStatusCheckAllClientMessage": "Toate listele sunt indisponibile datorită erorilor", "Name": "Nume", "MovieTitle": "Titlu Film", "Movies": "Filme", diff --git a/src/NzbDrone.Core/Localization/Core/sv.json b/src/NzbDrone.Core/Localization/Core/sv.json index f4a1ea612..9d463317c 100644 --- a/src/NzbDrone.Core/Localization/Core/sv.json +++ b/src/NzbDrone.Core/Localization/Core/sv.json @@ -203,8 +203,8 @@ "Options": "Alternativ", "NoChanges": "Inga ändringar", "NoChange": "Ingen förändring", - "NetImportStatusCheckSingleClientMessage": "Listor otillgängliga på grund av fel: {0}", - "NetImportStatusCheckAllClientMessage": "Samtliga listor otillgängliga på grund av fel", + "ImportListStatusCheckSingleClientMessage": "Listor otillgängliga på grund av fel: {0}", + "ImportListStatusCheckAllClientMessage": "Samtliga listor otillgängliga på grund av fel", "MovieTitle": "Filmtitel", "Movies": "Filmer", "MovieNaming": "Namngivning av film", diff --git a/src/NzbDrone.Core/Localization/Core/tr.json b/src/NzbDrone.Core/Localization/Core/tr.json index a2a3f332f..2a94c1f8b 100644 --- a/src/NzbDrone.Core/Localization/Core/tr.json +++ b/src/NzbDrone.Core/Localization/Core/tr.json @@ -29,8 +29,8 @@ "ProxyCheckBadRequestMessage": "Proxy ile test edilemedi. DurumKodu: {0}", "Proxy": "Proxy", "PreviewRename": "Ad değiştirmeyi ön izle", - "NetImportStatusCheckSingleClientMessage": "Hatalar nedeniyle kullanılamayan listeler: {0}", - "NetImportStatusCheckAllClientMessage": "Hatalar nedeniyle tüm listeler kullanılamıyor", + "ImportListStatusCheckSingleClientMessage": "Hatalar nedeniyle kullanılamayan listeler: {0}", + "ImportListStatusCheckAllClientMessage": "Hatalar nedeniyle tüm listeler kullanılamıyor", "MonitoredOnly": "Sadece İzlenenler", "MetadataSettingsSummary": "Filmler içe aktarıldığında veya yenilenince meta veri dosyaları oluştur", "Metadata": "Meta veri", diff --git a/src/NzbDrone.Core/Messaging/Commands/Command.cs b/src/NzbDrone.Core/Messaging/Commands/Command.cs index 2e11db195..0a41c9078 100644 --- a/src/NzbDrone.Core/Messaging/Commands/Command.cs +++ b/src/NzbDrone.Core/Messaging/Commands/Command.cs @@ -23,6 +23,7 @@ namespace NzbDrone.Core.Messaging.Commands public virtual string CompletionMessage => "Completed"; public virtual bool RequiresDiskAccess => false; public virtual bool IsExclusive => false; + public virtual bool IsTypeExclusive => false; public string Name { get; private set; } public DateTime? LastExecutionTime { get; set; } diff --git a/src/NzbDrone.Core/Messaging/Commands/CommandQueue.cs b/src/NzbDrone.Core/Messaging/Commands/CommandQueue.cs index d8489785d..de526541f 100644 --- a/src/NzbDrone.Core/Messaging/Commands/CommandQueue.cs +++ b/src/NzbDrone.Core/Messaging/Commands/CommandQueue.cs @@ -128,22 +128,26 @@ namespace NzbDrone.Core.Messaging.Commands { var startedCommands = _items.Where(c => c.Status == CommandStatus.Started) .ToList(); - var localItem = _items.Where(c => + + var exclusiveTypes = startedCommands.Where(x => x.Body.IsTypeExclusive) + .Select(x => x.Body.Name) + .ToList(); + + var queuedCommands = _items.Where(c => c.Status == CommandStatus.Queued); + + if (startedCommands.Any(x => x.Body.RequiresDiskAccess)) + { + queuedCommands = queuedCommands.Where(c => !c.Body.RequiresDiskAccess); + } + + if (startedCommands.Any(x => x.Body.IsTypeExclusive)) { - // If an executing command requires disk access don't return a command that - // requires disk access. A lower priority or later queued task could be returned - // instead, but that will allow other tasks to execute whiule waiting for disk access. - if (startedCommands.Any(x => x.Body.RequiresDiskAccess)) - { - return c.Status == CommandStatus.Queued && - !c.Body.RequiresDiskAccess; - } - - return c.Status == CommandStatus.Queued; - }) - .OrderByDescending(c => c.Priority) - .ThenBy(c => c.QueuedAt) - .FirstOrDefault(); + queuedCommands = queuedCommands.Where(c => !exclusiveTypes.Any(x => x == c.Body.Name)); + } + + var localItem = queuedCommands.OrderByDescending(c => c.Priority) + .ThenBy(c => c.QueuedAt) + .FirstOrDefault(); // Nothing queued that meets the requirements if (localItem == null) @@ -169,6 +173,7 @@ namespace NzbDrone.Core.Messaging.Commands { localItem.StartedAt = DateTime.UtcNow; localItem.Status = CommandStatus.Started; + item = localItem; } } diff --git a/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs b/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs index b6af965c7..e8a055113 100644 --- a/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs +++ b/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs @@ -25,7 +25,6 @@ namespace NzbDrone.Core.MetadataSource.SkyHook private readonly IHttpClient _httpClient; private readonly Logger _logger; - private readonly IHttpRequestBuilderFactory _movieBuilder; private readonly IHttpRequestBuilderFactory _radarrMetadata; private readonly IConfigService _configService; private readonly IMovieService _movieService; @@ -39,7 +38,6 @@ namespace NzbDrone.Core.MetadataSource.SkyHook Logger logger) { _httpClient = httpClient; - _movieBuilder = requestBuilder.TMDB; _radarrMetadata = requestBuilder.RadarrMetadata; _configService = configService; _movieService = movieService; @@ -254,10 +252,16 @@ namespace NzbDrone.Core.MetadataSource.SkyHook { try { - Movie newMovie = movie; + var newMovie = movie; + if (movie.TmdbId > 0) { - newMovie = GetMovieInfo(movie.TmdbId).Item1; + newMovie = _movieService.FindByTmdbId(movie.TmdbId); + + if (newMovie == null) + { + newMovie = GetMovieInfo(movie.TmdbId).Item1; + } } else if (movie.ImdbId.IsNotNullOrWhiteSpace()) { diff --git a/src/NzbDrone.Core/Movies/MovieRepository.cs b/src/NzbDrone.Core/Movies/MovieRepository.cs index 58cee2c9c..c930e68ef 100644 --- a/src/NzbDrone.Core/Movies/MovieRepository.cs +++ b/src/NzbDrone.Core/Movies/MovieRepository.cs @@ -27,6 +27,8 @@ namespace NzbDrone.Core.Movies PagingSpec MoviesWhereCutoffUnmet(PagingSpec pagingSpec, List qualitiesBelowCutoff); Movie FindByPath(string path); List AllMoviePaths(); + List AllMovieTmdbIds(); + List GetRecommendations(); } public class MovieRepository : BasicRepository, IMovieRepository @@ -219,5 +221,30 @@ namespace NzbDrone.Core.Movies return conn.Query("SELECT Path FROM Movies").ToList(); } } + + public List AllMovieTmdbIds() + { + using (var conn = _database.OpenConnection()) + { + return conn.Query("SELECT TmdbId FROM Movies").ToList(); + } + } + + public List GetRecommendations() + { + var recommendations = new List>(); + var tmdbIds = AllMovieTmdbIds(); + + using (var conn = _database.OpenConnection()) + { + recommendations = conn.Query>("SELECT Recommendations FROM Movies ORDER BY id DESC LIMIT 100").ToList(); + } + + return recommendations.SelectMany(x => x) + .Where(r => !tmdbIds.Any(m => m == r)) + .Distinct() + .Take(100) + .ToList(); + } } } diff --git a/src/NzbDrone.Core/Movies/MovieService.cs b/src/NzbDrone.Core/Movies/MovieService.cs index 35e1a964b..2ab02821e 100644 --- a/src/NzbDrone.Core/Movies/MovieService.cs +++ b/src/NzbDrone.Core/Movies/MovieService.cs @@ -30,6 +30,7 @@ namespace NzbDrone.Core.Movies Movie FindByTitleSlug(string slug); Movie FindByPath(string path); List AllMoviePaths(); + List AllMovieTmdbIds(); bool MovieExists(Movie movie); List GetMoviesByFileId(int fileId); List GetMoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored); @@ -42,7 +43,7 @@ namespace NzbDrone.Core.Movies Movie UpdateMovie(Movie movie); List UpdateMovie(List movie, bool useExistingRelativeFolder); List FilterExistingMovies(List movies); - List GetRecommendedMovies(); + List GetRecommendedTmdbIds(); bool MoviePathExists(string folder); void RemoveAddOptions(Movie movie); } @@ -181,6 +182,11 @@ namespace NzbDrone.Core.Movies return _movieRepository.AllMoviePaths(); } + public List AllMovieTmdbIds() + { + return _movieRepository.AllMovieTmdbIds(); + } + public void DeleteMovie(int movieId, bool deleteFiles, bool addExclusion = false) { var movie = _movieRepository.Get(movieId); @@ -351,26 +357,9 @@ namespace NzbDrone.Core.Movies return ret; } - public List GetRecommendedMovies() + public List GetRecommendedTmdbIds() { - // Get all recommended movies, plus all movies on enabled lists - var netImportMovies = new List(); - - var allMovies = GetAllMovies(); - - // Ensure we only return distinct ids that do not exist in DB already, first 100 that are from latest movies add first - var distinctRecommendations = allMovies.OrderByDescending(x => x.Added) - .SelectMany(m => m.Recommendations.Select(c => c)) - .Where(r => !allMovies.Any(m => m.TmdbId == r)) - .Distinct() - .Take(100); - - foreach (var recommendation in distinctRecommendations) - { - netImportMovies.Add(new Movie { TmdbId = recommendation }); - } - - return netImportMovies; + return _movieRepository.GetRecommendations(); } public void Handle(MovieFileAddedEvent message) diff --git a/src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoImport.cs b/src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoImport.cs deleted file mode 100644 index 429a4eb33..000000000 --- a/src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoImport.cs +++ /dev/null @@ -1,31 +0,0 @@ -using NLog; -using NzbDrone.Common.Http; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Parser; - -namespace NzbDrone.Core.NetImport.CouchPotato -{ - public class CouchPotatoImport : HttpNetImportBase - { - public override string Name => "CouchPotato"; - - public override NetImportType ListType => NetImportType.Program; - public override bool Enabled => true; - public override bool EnableAuto => false; - - public CouchPotatoImport(IHttpClient httpClient, INetImportStatusService netImportStatusService, IConfigService configService, IParsingService parsingService, Logger logger) - : base(httpClient, netImportStatusService, configService, parsingService, logger) - { - } - - public override INetImportRequestGenerator GetRequestGenerator() - { - return new CouchPotatoRequestGenerator() { Settings = Settings }; - } - - public override IParseNetImportResponse GetParser() - { - return new CouchPotatoParser(Settings); - } - } -} diff --git a/src/NzbDrone.Core/NetImport/Exceptions/NetImportException.cs b/src/NzbDrone.Core/NetImport/Exceptions/NetImportException.cs deleted file mode 100644 index d3444d991..000000000 --- a/src/NzbDrone.Core/NetImport/Exceptions/NetImportException.cs +++ /dev/null @@ -1,23 +0,0 @@ -using NzbDrone.Common.Exceptions; - -namespace NzbDrone.Core.NetImport.Exceptions -{ - public class NetImportException : NzbDroneException - { - private readonly NetImportResponse _netImportResponse; - - public NetImportException(NetImportResponse response, string message, params object[] args) - : base(message, args) - { - _netImportResponse = response; - } - - public NetImportException(NetImportResponse response, string message) - : base(message) - { - _netImportResponse = response; - } - - public NetImportResponse Response => _netImportResponse; - } -} diff --git a/src/NzbDrone.Core/NetImport/INetImport.cs b/src/NzbDrone.Core/NetImport/INetImport.cs deleted file mode 100644 index e4c69ec2d..000000000 --- a/src/NzbDrone.Core/NetImport/INetImport.cs +++ /dev/null @@ -1,13 +0,0 @@ -using NzbDrone.Core.ThingiProvider; - -namespace NzbDrone.Core.NetImport -{ - public interface INetImport : IProvider - { - bool Enabled { get; } - bool EnableAuto { get; } - - NetImportType ListType { get; } - NetImportFetchResult Fetch(); - } -} diff --git a/src/NzbDrone.Core/NetImport/INetImportRequestGenerator.cs b/src/NzbDrone.Core/NetImport/INetImportRequestGenerator.cs deleted file mode 100644 index ce89ef023..000000000 --- a/src/NzbDrone.Core/NetImport/INetImportRequestGenerator.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace NzbDrone.Core.NetImport -{ - public interface INetImportRequestGenerator - { - NetImportPageableRequestChain GetMovies(); - } -} diff --git a/src/NzbDrone.Core/NetImport/IProcessNetImportResponse.cs b/src/NzbDrone.Core/NetImport/IProcessNetImportResponse.cs deleted file mode 100644 index c5663b9d3..000000000 --- a/src/NzbDrone.Core/NetImport/IProcessNetImportResponse.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; -using NzbDrone.Core.Movies; - -namespace NzbDrone.Core.NetImport -{ - public interface IParseNetImportResponse - { - IList ParseResponse(NetImportResponse netMovieImporterResponse); - } -} diff --git a/src/NzbDrone.Core/NetImport/NetImportFactory.cs b/src/NzbDrone.Core/NetImport/NetImportFactory.cs deleted file mode 100644 index 122344d79..000000000 --- a/src/NzbDrone.Core/NetImport/NetImportFactory.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using NLog; -using NzbDrone.Common.Composition; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.ThingiProvider; - -namespace NzbDrone.Core.NetImport -{ - public interface INetImportFactory : IProviderFactory - { - List Enabled(); - - List Discoverable(); - } - - public class NetImportFactory : ProviderFactory, INetImportFactory - { - private readonly INetImportRepository _providerRepository; - private readonly Logger _logger; - - public NetImportFactory(INetImportRepository providerRepository, - IEnumerable providers, - IContainer container, - IEventAggregator eventAggregator, - Logger logger) - : base(providerRepository, providers, container, eventAggregator, logger) - { - _providerRepository = providerRepository; - _logger = logger; - } - - protected override List Active() - { - return base.Active().Where(c => c.Enabled).ToList(); - } - - public override void SetProviderCharacteristics(INetImport provider, NetImportDefinition definition) - { - base.SetProviderCharacteristics(provider, definition); - - definition.ListType = provider.ListType; - } - - public List Enabled() - { - var enabledImporters = GetAvailableProviders().Where(n => ((NetImportDefinition)n.Definition).Enabled); - var indexers = FilterBlockedIndexers(enabledImporters); - return indexers.ToList(); - } - - public List Discoverable() - { - var enabledImporters = GetAvailableProviders().Where(n => (n.GetType() == typeof(RadarrList.RadarrListImport) || n.GetType() == typeof(TMDb.Popular.TMDbPopularImport))); - var indexers = FilterBlockedIndexers(enabledImporters); - return indexers.ToList(); - } - - private IEnumerable FilterBlockedIndexers(IEnumerable importers) - { - foreach (var importer in importers) - { - yield return importer; - } - } - } -} diff --git a/src/NzbDrone.Core/NetImport/NetImportPageableRequest.cs b/src/NzbDrone.Core/NetImport/NetImportPageableRequest.cs deleted file mode 100644 index 50a43fce9..000000000 --- a/src/NzbDrone.Core/NetImport/NetImportPageableRequest.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections; -using System.Collections.Generic; - -namespace NzbDrone.Core.NetImport -{ - public class NetImportPageableRequest : IEnumerable - { - private readonly IEnumerable _enumerable; - - public NetImportPageableRequest(IEnumerable enumerable) - { - _enumerable = enumerable; - } - - public IEnumerator GetEnumerator() - { - return _enumerable.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return _enumerable.GetEnumerator(); - } - } -} diff --git a/src/NzbDrone.Core/NetImport/NetImportPageableRequestChain.cs b/src/NzbDrone.Core/NetImport/NetImportPageableRequestChain.cs deleted file mode 100644 index 9b2f5ca87..000000000 --- a/src/NzbDrone.Core/NetImport/NetImportPageableRequestChain.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace NzbDrone.Core.NetImport -{ - public class NetImportPageableRequestChain - { - private List> _chains; - - public NetImportPageableRequestChain() - { - _chains = new List>(); - _chains.Add(new List()); - } - - public int Tiers => _chains.Count; - - public IEnumerable GetAllTiers() - { - return _chains.SelectMany(v => v); - } - - public IEnumerable GetTier(int index) - { - return _chains[index]; - } - - public void Add(IEnumerable request) - { - if (request == null) - { - return; - } - - _chains.Last().Add(new NetImportPageableRequest(request)); - } - - public void AddTier(IEnumerable request) - { - AddTier(); - Add(request); - } - - public void AddTier() - { - if (_chains.Last().Count == 0) - { - return; - } - - _chains.Add(new List()); - } - } -} diff --git a/src/NzbDrone.Core/NetImport/NetImportRepository.cs b/src/NzbDrone.Core/NetImport/NetImportRepository.cs deleted file mode 100644 index 77ccfa092..000000000 --- a/src/NzbDrone.Core/NetImport/NetImportRepository.cs +++ /dev/null @@ -1,24 +0,0 @@ -using NzbDrone.Core.Datastore; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.ThingiProvider; - -namespace NzbDrone.Core.NetImport -{ - public interface INetImportRepository : IProviderRepository - { - void UpdateSettings(NetImportDefinition model); - } - - public class NetImportRepository : ProviderRepository, INetImportRepository - { - public NetImportRepository(IMainDatabase database, IEventAggregator eventAggregator) - : base(database, eventAggregator) - { - } - - public void UpdateSettings(NetImportDefinition model) - { - SetFields(model, m => m.Settings); - } - } -} diff --git a/src/NzbDrone.Core/NetImport/NetImportSearchService.cs b/src/NzbDrone.Core/NetImport/NetImportSearchService.cs deleted file mode 100644 index 8bf9c3ae4..000000000 --- a/src/NzbDrone.Core/NetImport/NetImportSearchService.cs +++ /dev/null @@ -1,205 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using NLog; -using NzbDrone.Common.Extensions; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Messaging.Commands; -using NzbDrone.Core.MetadataSource; -using NzbDrone.Core.Movies; -using NzbDrone.Core.NetImport.ImportExclusions; - -namespace NzbDrone.Core.NetImport -{ - public interface IFetchNetImport - { - NetImportFetchResult Fetch(int listId, bool onlyEnableAuto); - List FetchAndFilter(int listId, bool onlyEnableAuto); - } - - public class NetImportSearchService : IFetchNetImport, IExecute - { - private readonly Logger _logger; - private readonly INetImportFactory _netImportFactory; - private readonly IMovieService _movieService; - private readonly IAddMovieService _addMovieService; - private readonly ISearchForNewMovie _movieSearch; - private readonly IConfigService _configService; - private readonly IImportExclusionsService _exclusionService; - - public NetImportSearchService(INetImportFactory netImportFactory, - IMovieService movieService, - IAddMovieService addMovieService, - ISearchForNewMovie movieSearch, - IConfigService configService, - IImportExclusionsService exclusionService, - Logger logger) - { - _netImportFactory = netImportFactory; - _movieService = movieService; - _addMovieService = addMovieService; - _movieSearch = movieSearch; - _exclusionService = exclusionService; - _logger = logger; - _configService = configService; - } - - public NetImportFetchResult Fetch(int listId, bool onlyEnableAuto = false) - { - return MovieListSearch(listId, onlyEnableAuto); - } - - public List FetchAndFilter(int listId, bool onlyEnableAuto) - { - var movies = MovieListSearch(listId, onlyEnableAuto).Movies; - - return _movieService.FilterExistingMovies(movies.ToList()); - } - - public NetImportFetchResult MovieListSearch(int listId, bool onlyEnableAuto = false) - { - var movies = new List(); - var anyFailure = false; - - var importLists = _netImportFactory.GetAvailableProviders(); - - var lists = listId == 0 ? importLists : importLists.Where(n => ((NetImportDefinition)n.Definition).Id == listId); - - if (onlyEnableAuto) - { - lists = importLists.Where(a => ((NetImportDefinition)a.Definition).EnableAuto); - } - - foreach (var list in lists) - { - var result = list.Fetch(); - movies.AddRange(result.Movies); - anyFailure |= result.AnyFailure; - } - - _logger.Debug("Found {0} movies from list(s) {1}", movies.Count, string.Join(", ", lists.Select(l => l.Definition.Name))); - - return new NetImportFetchResult - { - Movies = movies.DistinctBy(x => - { - if (x.TmdbId != 0) - { - return x.TmdbId.ToString(); - } - - if (x.ImdbId.IsNotNullOrWhiteSpace()) - { - return x.ImdbId; - } - - return x.Title; - }).ToList(), - AnyFailure = anyFailure - }; - } - - public void Execute(NetImportSyncCommand message) - { - //if there are no lists that are enabled for automatic import then dont do anything - if (_netImportFactory.GetAvailableProviders().Where(a => ((NetImportDefinition)a.Definition).EnableAuto).Empty()) - { - _logger.Info("No lists are enabled for auto-import."); - return; - } - - var result = Fetch(0, true); - var listedMovies = result.Movies.ToList(); - - if (!result.AnyFailure) - { - CleanLibrary(listedMovies); - } - - listedMovies = listedMovies.Where(x => !_movieService.MovieExists(x)).ToList(); - if (listedMovies.Any()) - { - _logger.Info($"Found {listedMovies.Count()} movies on your auto enabled lists not in your library"); - } - - var importExclusions = new List(); - var moviesToAdd = new List(); - - foreach (var movie in listedMovies) - { - var mapped = _movieSearch.MapMovieToTmdbMovie(movie); - - if (mapped != null && mapped.TmdbId > 0) - { - if (_exclusionService.IsMovieExcluded(mapped.TmdbId)) - { - _logger.Debug($"{mapped.Title} ({mapped.TmdbId}) will not be added since it was found on the exclusions list"); - } - else if (_movieService.MovieExists(mapped)) - { - _logger.Trace($"{mapped.Title} ({mapped.TmdbId}) will not be added since it exists in Library"); - } - else - { - if (!moviesToAdd.Any(c => c.TmdbId == mapped.TmdbId)) - { - mapped.AddOptions = new AddMovieOptions { SearchForMovie = true }; - moviesToAdd.Add(mapped); - } - } - } - } - - if (moviesToAdd.Any()) - { - _logger.Info($"Adding {moviesToAdd.Count()} movies from your auto enabled lists to library"); - } - - _addMovieService.AddMovies(moviesToAdd, true); - } - - private void CleanLibrary(List movies) - { - var moviesToUpdate = new List(); - - if (_configService.ListSyncLevel == "disabled") - { - return; - } - - var moviesInLibrary = _movieService.GetAllMovies(); - foreach (var movie in moviesInLibrary) - { - var movieExists = movies.Any(c => c.TmdbId == movie.TmdbId || c.ImdbId == movie.ImdbId); - - if (!movieExists) - { - switch (_configService.ListSyncLevel) - { - case "logOnly": - _logger.Info("{0} was in your library, but not found in your lists --> You might want to unmonitor or remove it", movie); - break; - case "keepAndUnmonitor": - _logger.Info("{0} was in your library, but not found in your lists --> Keeping in library but Unmonitoring it", movie); - movie.Monitored = false; - moviesToUpdate.Add(movie); - break; - case "removeAndKeep": - _logger.Info("{0} was in your library, but not found in your lists --> Removing from library (keeping files)", movie); - _movieService.DeleteMovie(movie.Id, false); - break; - case "removeAndDelete": - _logger.Info("{0} was in your library, but not found in your lists --> Removing from library and deleting files", movie); - _movieService.DeleteMovie(movie.Id, true); - - //TODO: for some reason the files are not deleted in this case... any idea why? - break; - default: - break; - } - } - } - - _movieService.UpdateMovie(moviesToUpdate, true); - } - } -} diff --git a/src/NzbDrone.Core/NetImport/NetImportStatusRepository.cs b/src/NzbDrone.Core/NetImport/NetImportStatusRepository.cs deleted file mode 100644 index addd58f6b..000000000 --- a/src/NzbDrone.Core/NetImport/NetImportStatusRepository.cs +++ /dev/null @@ -1,18 +0,0 @@ -using NzbDrone.Core.Datastore; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.ThingiProvider.Status; - -namespace NzbDrone.Core.NetImport -{ - public interface INetImportStatusRepository : IProviderStatusRepository - { - } - - public class NetImportStatusRepository : ProviderStatusRepository, INetImportStatusRepository - { - public NetImportStatusRepository(IMainDatabase database, IEventAggregator eventAggregator) - : base(database, eventAggregator) - { - } - } -} diff --git a/src/NzbDrone.Core/NetImport/NetImportSyncCommand.cs b/src/NzbDrone.Core/NetImport/NetImportSyncCommand.cs deleted file mode 100644 index 02584e348..000000000 --- a/src/NzbDrone.Core/NetImport/NetImportSyncCommand.cs +++ /dev/null @@ -1,11 +0,0 @@ -using NzbDrone.Core.Messaging.Commands; - -namespace NzbDrone.Core.NetImport -{ - public class NetImportSyncCommand : Command - { - public override bool SendUpdatesToClient => true; - - public int ListId = 0; - } -} diff --git a/src/NzbDrone.Core/NetImport/RSSImport/RSSImportRequestGenerator.cs b/src/NzbDrone.Core/NetImport/RSSImport/RSSImportRequestGenerator.cs deleted file mode 100644 index 9f59da5d4..000000000 --- a/src/NzbDrone.Core/NetImport/RSSImport/RSSImportRequestGenerator.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using NzbDrone.Common.Http; - -namespace NzbDrone.Core.NetImport.RSSImport -{ - public class RSSImportRequestGenerator : INetImportRequestGenerator - { - public RSSImportSettings Settings { get; set; } - - public virtual NetImportPageableRequestChain GetMovies() - { - var pageableRequests = new NetImportPageableRequestChain(); - - pageableRequests.Add(GetMovies(null)); - - return pageableRequests; - } - - //public NetImportPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - //{ - // return new NetImportPageableRequestChain(); - //} - private IEnumerable GetMovies(string searchParameters) - { - var request = new NetImportRequest($"{Settings.Link.Trim()}", HttpAccept.Rss); - yield return request; - } - } -} diff --git a/src/NzbDrone.Core/NetImport/RadarrList/RadarrListRequestGenerator.cs b/src/NzbDrone.Core/NetImport/RadarrList/RadarrListRequestGenerator.cs deleted file mode 100644 index 18643db27..000000000 --- a/src/NzbDrone.Core/NetImport/RadarrList/RadarrListRequestGenerator.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Generic; -using NLog; -using NzbDrone.Common.Http; - -namespace NzbDrone.Core.NetImport.RadarrList -{ - public class RadarrListRequestGenerator : INetImportRequestGenerator - { - public RadarrListSettings Settings { get; set; } - public IHttpClient HttpClient { get; set; } - public Logger Logger { get; set; } - - public virtual NetImportPageableRequestChain GetMovies() - { - var pageableRequests = new NetImportPageableRequestChain(); - - var request = new NetImportRequest(Settings.Url, HttpAccept.Json); - - request.HttpRequest.SuppressHttpError = true; - - pageableRequests.Add(new List { request }); - return pageableRequests; - } - } -} diff --git a/src/NzbDrone.Core/NetImport/StevenLu/StevenLuParser.cs b/src/NzbDrone.Core/NetImport/StevenLu/StevenLuParser.cs deleted file mode 100644 index 859aa52de..000000000 --- a/src/NzbDrone.Core/NetImport/StevenLu/StevenLuParser.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Collections.Generic; -using System.Net; -using Newtonsoft.Json; -using NzbDrone.Common.Extensions; -using NzbDrone.Core.NetImport.Exceptions; - -namespace NzbDrone.Core.NetImport.StevenLu -{ - public class StevenLuParser : IParseNetImportResponse - { - private NetImportResponse _importResponse; - - public StevenLuParser() - { - } - - public IList ParseResponse(NetImportResponse importResponse) - { - _importResponse = importResponse; - - var movies = new List(); - - if (!PreProcess(_importResponse)) - { - return movies; - } - - var jsonResponse = JsonConvert.DeserializeObject>(_importResponse.Content); - - // no movies were return - if (jsonResponse == null) - { - return movies; - } - - foreach (var item in jsonResponse) - { - movies.AddIfNotNull(new Movies.Movie() - { - Title = item.title, - ImdbId = item.imdb_id, - }); - } - - return movies; - } - - protected virtual bool PreProcess(NetImportResponse netImportResponse) - { - if (netImportResponse.HttpResponse.StatusCode != HttpStatusCode.OK) - { - throw new NetImportException(netImportResponse, "StevenLu API call resulted in an unexpected StatusCode [{0}]", netImportResponse.HttpResponse.StatusCode); - } - - if (netImportResponse.HttpResponse.Headers.ContentType != null && netImportResponse.HttpResponse.Headers.ContentType.Contains("text/json") && - netImportResponse.HttpRequest.Headers.Accept != null && !netImportResponse.HttpRequest.Headers.Accept.Contains("text/json")) - { - throw new NetImportException(netImportResponse, "StevenLu responded with html content. Site is likely blocked or unavailable."); - } - - return true; - } - } -} diff --git a/src/NzbDrone.Core/NetImport/StevenLu/StevenLuRequestGenerator.cs b/src/NzbDrone.Core/NetImport/StevenLu/StevenLuRequestGenerator.cs deleted file mode 100644 index 4d44e3e69..000000000 --- a/src/NzbDrone.Core/NetImport/StevenLu/StevenLuRequestGenerator.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; -using NzbDrone.Common.Http; - -namespace NzbDrone.Core.NetImport.StevenLu -{ - public class StevenLuRequestGenerator : INetImportRequestGenerator - { - public StevenLuSettings Settings { get; set; } - - public virtual NetImportPageableRequestChain GetMovies() - { - var pageableRequests = new NetImportPageableRequestChain(); - pageableRequests.Add(GetMovies(null)); - return pageableRequests; - } - - private IEnumerable GetMovies(string searchParameters) - { - var request = new NetImportRequest($"{Settings.Link.Trim()}", HttpAccept.Json); - yield return request; - } - } -} diff --git a/src/NzbDrone.Core/NetImport/Trakt/TraktParser.cs b/src/NzbDrone.Core/NetImport/Trakt/TraktParser.cs deleted file mode 100644 index c7dc6ffdf..000000000 --- a/src/NzbDrone.Core/NetImport/Trakt/TraktParser.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Collections.Generic; -using System.Net; -using Newtonsoft.Json; -using NzbDrone.Common.Extensions; -using NzbDrone.Core.NetImport.Exceptions; -using NzbDrone.Core.Notifications.Trakt.Resource; - -namespace NzbDrone.Core.NetImport.Trakt -{ - public class TraktParser : IParseNetImportResponse - { - private NetImportResponse _importResponse; - - public TraktParser() - { - } - - public virtual IList ParseResponse(NetImportResponse importResponse) - { - _importResponse = importResponse; - - var movies = new List(); - - if (!PreProcess(_importResponse)) - { - return movies; - } - - var jsonResponse = JsonConvert.DeserializeObject>(_importResponse.Content); - - // no movies were return - if (jsonResponse == null) - { - return movies; - } - - foreach (var movie in jsonResponse) - { - movies.AddIfNotNull(new Movies.Movie() - { - Title = movie.Movie.Title, - ImdbId = movie.Movie.Ids.Imdb, - TmdbId = movie.Movie.Ids.Tmdb, - Year = movie.Movie.Year ?? 0 - }); - } - - return movies; - } - - protected virtual bool PreProcess(NetImportResponse netImportResponse) - { - if (netImportResponse.HttpResponse.StatusCode != HttpStatusCode.OK) - { - throw new NetImportException(netImportResponse, "Trakt API call resulted in an unexpected StatusCode [{0}]", netImportResponse.HttpResponse.StatusCode); - } - - if (netImportResponse.HttpResponse.Headers.ContentType != null && netImportResponse.HttpResponse.Headers.ContentType.Contains("text/json") && - netImportResponse.HttpRequest.Headers.Accept != null && !netImportResponse.HttpRequest.Headers.Accept.Contains("text/json")) - { - throw new NetImportException(netImportResponse, "Trakt API responded with html content. Site is likely blocked or unavailable."); - } - - return true; - } - } -} diff --git a/src/NzbDrone.Core/Profiles/ProfileService.cs b/src/NzbDrone.Core/Profiles/ProfileService.cs index 25ba142f0..a21478edd 100644 --- a/src/NzbDrone.Core/Profiles/ProfileService.cs +++ b/src/NzbDrone.Core/Profiles/ProfileService.cs @@ -3,11 +3,11 @@ using System.Linq; using NLog; using NzbDrone.Core.CustomFormats; using NzbDrone.Core.CustomFormats.Events; +using NzbDrone.Core.ImportLists; using NzbDrone.Core.Languages; using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Movies; -using NzbDrone.Core.NetImport; using NzbDrone.Core.Qualities; namespace NzbDrone.Core.Profiles @@ -32,19 +32,19 @@ namespace NzbDrone.Core.Profiles private readonly IProfileRepository _profileRepository; private readonly ICustomFormatService _formatService; private readonly IMovieService _movieService; - private readonly INetImportFactory _netImportFactory; + private readonly IImportListFactory _importListFactory; private readonly Logger _logger; public ProfileService(IProfileRepository profileRepository, ICustomFormatService formatService, IMovieService movieService, - INetImportFactory netImportFactory, + IImportListFactory importListFactory, Logger logger) { _profileRepository = profileRepository; _formatService = formatService; _movieService = movieService; - _netImportFactory = netImportFactory; + _importListFactory = importListFactory; _logger = logger; } @@ -60,7 +60,7 @@ namespace NzbDrone.Core.Profiles public void Delete(int id) { - if (_movieService.GetAllMovies().Any(c => c.ProfileId == id) || _netImportFactory.All().Any(c => c.ProfileId == id)) + if (_movieService.GetAllMovies().Any(c => c.ProfileId == id) || _importListFactory.All().Any(c => c.ProfileId == id)) { throw new ProfileInUseException(id); } diff --git a/src/NzbDrone.Core/Tags/TagDetails.cs b/src/NzbDrone.Core/Tags/TagDetails.cs index 80ee15fa8..16c262176 100644 --- a/src/NzbDrone.Core/Tags/TagDetails.cs +++ b/src/NzbDrone.Core/Tags/TagDetails.cs @@ -10,7 +10,7 @@ namespace NzbDrone.Core.Tags public List MovieIds { get; set; } public List NotificationIds { get; set; } public List RestrictionIds { get; set; } - public List NetImportIds { get; set; } + public List ImportListIds { get; set; } public List DelayProfileIds { get; set; } public bool InUse diff --git a/src/NzbDrone.Core/Tags/TagService.cs b/src/NzbDrone.Core/Tags/TagService.cs index 73c4d3c6a..159f2df7a 100644 --- a/src/NzbDrone.Core/Tags/TagService.cs +++ b/src/NzbDrone.Core/Tags/TagService.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Linq; using NzbDrone.Core.Datastore; +using NzbDrone.Core.ImportLists; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Movies; -using NzbDrone.Core.NetImport; using NzbDrone.Core.Notifications; using NzbDrone.Core.Profiles.Delay; using NzbDrone.Core.Restrictions; @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Tags private readonly ITagRepository _repo; private readonly IEventAggregator _eventAggregator; private readonly IDelayProfileService _delayProfileService; - private readonly INetImportFactory _netImportFactory; + private readonly IImportListFactory _importListFactory; private readonly INotificationFactory _notificationFactory; private readonly IRestrictionService _restrictionService; private readonly IMovieService _movieService; @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Tags public TagService(ITagRepository repo, IEventAggregator eventAggregator, IDelayProfileService delayProfileService, - INetImportFactory netImportFactory, + IImportListFactory importListFactory, INotificationFactory notificationFactory, IRestrictionService restrictionService, IMovieService movieService) @@ -44,7 +44,7 @@ namespace NzbDrone.Core.Tags _repo = repo; _eventAggregator = eventAggregator; _delayProfileService = delayProfileService; - _netImportFactory = netImportFactory; + _importListFactory = importListFactory; _notificationFactory = notificationFactory; _restrictionService = restrictionService; _movieService = movieService; @@ -76,7 +76,7 @@ namespace NzbDrone.Core.Tags { var tag = GetTag(tagId); var delayProfiles = _delayProfileService.AllForTag(tagId); - var netImports = _netImportFactory.AllForTag(tagId); + var importLists = _importListFactory.AllForTag(tagId); var notifications = _notificationFactory.AllForTag(tagId); var restrictions = _restrictionService.AllForTag(tagId); var movies = _movieService.AllForTag(tagId); @@ -86,7 +86,7 @@ namespace NzbDrone.Core.Tags Id = tagId, Label = tag.Label, DelayProfileIds = delayProfiles.Select(c => c.Id).ToList(), - NetImportIds = netImports.Select(c => c.Id).ToList(), + ImportListIds = importLists.Select(c => c.Id).ToList(), NotificationIds = notifications.Select(c => c.Id).ToList(), RestrictionIds = restrictions.Select(c => c.Id).ToList(), MovieIds = movies.Select(c => c.Id).ToList() @@ -97,7 +97,7 @@ namespace NzbDrone.Core.Tags { var tags = All(); var delayProfiles = _delayProfileService.All(); - var netImports = _netImportFactory.All(); + var importLists = _importListFactory.All(); var notifications = _notificationFactory.All(); var restrictions = _restrictionService.All(); var movies = _movieService.GetAllMovies(); @@ -111,7 +111,7 @@ namespace NzbDrone.Core.Tags Id = tag.Id, Label = tag.Label, DelayProfileIds = delayProfiles.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(), - NetImportIds = netImports.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(), + ImportListIds = importLists.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(), NotificationIds = notifications.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(), RestrictionIds = restrictions.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(), MovieIds = movies.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList() diff --git a/src/Radarr.Api.V3/Config/NetImportConfigModule.cs b/src/Radarr.Api.V3/Config/NetImportConfigModule.cs index 653e196d1..e73deb651 100644 --- a/src/Radarr.Api.V3/Config/NetImportConfigModule.cs +++ b/src/Radarr.Api.V3/Config/NetImportConfigModule.cs @@ -3,18 +3,18 @@ using Radarr.Http.Validation; namespace Radarr.Api.V3.Config { - public class NetImportConfigModule : RadarrConfigModule + public class ImportListConfigModule : RadarrConfigModule { - public NetImportConfigModule(IConfigService configService) + public ImportListConfigModule(IConfigService configService) : base(configService) { - SharedValidator.RuleFor(c => c.NetImportSyncInterval) - .IsValidNetImportSyncInterval(); + SharedValidator.RuleFor(c => c.ImportListSyncInterval) + .IsValidImportListSyncInterval(); } - protected override NetImportConfigResource ToResource(IConfigService model) + protected override ImportListConfigResource ToResource(IConfigService model) { - return NetImportConfigResourceMapper.ToResource(model); + return ImportListConfigResourceMapper.ToResource(model); } } } diff --git a/src/Radarr.Api.V3/Config/NetImportConfigResource.cs b/src/Radarr.Api.V3/Config/NetImportConfigResource.cs index 8b4a2c803..2af075320 100644 --- a/src/Radarr.Api.V3/Config/NetImportConfigResource.cs +++ b/src/Radarr.Api.V3/Config/NetImportConfigResource.cs @@ -3,20 +3,20 @@ using Radarr.Http.REST; namespace Radarr.Api.V3.Config { - public class NetImportConfigResource : RestResource + public class ImportListConfigResource : RestResource { - public int NetImportSyncInterval { get; set; } + public int ImportListSyncInterval { get; set; } public string ListSyncLevel { get; set; } public string ImportExclusions { get; set; } } - public static class NetImportConfigResourceMapper + public static class ImportListConfigResourceMapper { - public static NetImportConfigResource ToResource(IConfigService model) + public static ImportListConfigResource ToResource(IConfigService model) { - return new NetImportConfigResource + return new ImportListConfigResource { - NetImportSyncInterval = model.NetImportSyncInterval, + ImportListSyncInterval = model.ImportListSyncInterval, ListSyncLevel = model.ListSyncLevel, ImportExclusions = model.ImportExclusions }; diff --git a/src/Radarr.Api.V3/NetImport/ImportExclusionsModule.cs b/src/Radarr.Api.V3/ImportLists/ImportExclusionsModule.cs similarity index 66% rename from src/Radarr.Api.V3/NetImport/ImportExclusionsModule.cs rename to src/Radarr.Api.V3/ImportLists/ImportExclusionsModule.cs index 44d650b09..9d4c69bda 100644 --- a/src/Radarr.Api.V3/NetImport/ImportExclusionsModule.cs +++ b/src/Radarr.Api.V3/ImportLists/ImportExclusionsModule.cs @@ -1,24 +1,26 @@ using System.Collections.Generic; using FluentValidation; -using NzbDrone.Core.NetImport; -using NzbDrone.Core.NetImport.ImportExclusions; +using NzbDrone.Core.ImportLists.ImportExclusions; using Radarr.Http; using Radarr.Http.Extensions; -namespace Radarr.Api.V3.NetImport +namespace Radarr.Api.V3.ImportLists { public class ImportExclusionsModule : RadarrRestModule { private readonly IImportExclusionsService _exclusionService; - public ImportExclusionsModule(NetImportFactory netImportFactory, IImportExclusionsService exclusionService) + public ImportExclusionsModule(IImportExclusionsService exclusionService) : base("exclusions") { _exclusionService = exclusionService; + GetResourceAll = GetAll; DeleteResource = RemoveExclusion; + CreateResource = AddExclusion; GetResourceById = GetById; - Post("/", x => AddExclusions()); + UpdateResource = UpdateExclusion; + Post("/bulk", x => AddExclusions()); SharedValidator.RuleFor(c => c.TmdbId).GreaterThan(0); SharedValidator.RuleFor(c => c.MovieTitle).NotEmpty(); @@ -35,12 +37,24 @@ namespace Radarr.Api.V3.NetImport return _exclusionService.GetById(id).ToResource(); } + private void UpdateExclusion(ImportExclusionsResource exclusionResource) + { + var model = exclusionResource.ToModel(); + _exclusionService.Update(model); + } + + public int AddExclusion(ImportExclusionsResource exclusionResource) + { + var model = exclusionResource.ToModel(); + + return _exclusionService.AddExclusion(model).Id; + } + public object AddExclusions() { var resource = Request.Body.FromJson>(); var newMovies = resource.ToModel(); - // TODO: Add some more validation here and auto pull the title if not provided return _exclusionService.AddExclusions(newMovies).ToResource(); } diff --git a/src/Radarr.Api.V3/NetImport/ImportExclusionsResource.cs b/src/Radarr.Api.V3/ImportLists/ImportExclusionsResource.cs similarity index 92% rename from src/Radarr.Api.V3/NetImport/ImportExclusionsResource.cs rename to src/Radarr.Api.V3/ImportLists/ImportExclusionsResource.cs index 123ed1098..78ec75099 100644 --- a/src/Radarr.Api.V3/NetImport/ImportExclusionsResource.cs +++ b/src/Radarr.Api.V3/ImportLists/ImportExclusionsResource.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Linq; -using NzbDrone.Core.NetImport.ImportExclusions; +using NzbDrone.Core.ImportLists.ImportExclusions; -namespace Radarr.Api.V3.NetImport +namespace Radarr.Api.V3.ImportLists { public class ImportExclusionsResource : ProviderResource { @@ -39,6 +39,7 @@ namespace Radarr.Api.V3.NetImport { return new ImportExclusion { + Id = resource.Id, TmdbId = resource.TmdbId, MovieTitle = resource.MovieTitle, MovieYear = resource.MovieYear diff --git a/src/Radarr.Api.V3/NetImport/NetImportModule.cs b/src/Radarr.Api.V3/ImportLists/ImportListModule.cs similarity index 52% rename from src/Radarr.Api.V3/NetImport/NetImportModule.cs rename to src/Radarr.Api.V3/ImportLists/ImportListModule.cs index 6034a917d..0aa369df7 100644 --- a/src/Radarr.Api.V3/NetImport/NetImportModule.cs +++ b/src/Radarr.Api.V3/ImportLists/ImportListModule.cs @@ -1,16 +1,16 @@ using FluentValidation; -using NzbDrone.Core.NetImport; +using NzbDrone.Core.ImportLists; using NzbDrone.Core.Validation; using NzbDrone.Core.Validation.Paths; -namespace Radarr.Api.V3.NetImport +namespace Radarr.Api.V3.ImportLists { - public class NetImportModule : ProviderModuleBase + public class ImportListModule : ProviderModuleBase { - public static readonly NetImportResourceMapper ResourceMapper = new NetImportResourceMapper(); + public static readonly ImportListResourceMapper ResourceMapper = new ImportListResourceMapper(); - public NetImportModule(NetImportFactory netImportFactory, ProfileExistsValidator profileExistsValidator) - : base(netImportFactory, "netimport", ResourceMapper) + public ImportListModule(ImportListFactory importListFactory, ProfileExistsValidator profileExistsValidator) + : base(importListFactory, "importlist", ResourceMapper) { SharedValidator.RuleFor(c => c.RootFolderPath).IsValidPath(); SharedValidator.RuleFor(c => c.MinimumAvailability).NotNull(); @@ -18,7 +18,7 @@ namespace Radarr.Api.V3.NetImport SharedValidator.RuleFor(c => c.QualityProfileId).SetValidator(profileExistsValidator); } - protected override void Validate(NetImportDefinition definition, bool includeWarnings) + protected override void Validate(ImportListDefinition definition, bool includeWarnings) { if (!definition.Enable) { diff --git a/src/Radarr.Api.V3/ImportLists/ImportListMoviesModule.cs b/src/Radarr.Api.V3/ImportLists/ImportListMoviesModule.cs new file mode 100644 index 000000000..8fbb70d7a --- /dev/null +++ b/src/Radarr.Api.V3/ImportLists/ImportListMoviesModule.cs @@ -0,0 +1,117 @@ +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.ImportLists.ImportExclusions; +using NzbDrone.Core.ImportLists.ImportListMovies; +using NzbDrone.Core.MediaCover; +using NzbDrone.Core.MetadataSource; +using NzbDrone.Core.Movies; +using NzbDrone.Core.Organizer; +using Radarr.Http; +using Radarr.Http.Extensions; + +namespace Radarr.Api.V3.ImportLists +{ + public class ImportListMoviesModule : RadarrRestModule + { + private readonly IMovieService _movieService; + private readonly IProvideMovieInfo _movieInfo; + private readonly IBuildFileNames _fileNameBuilder; + private readonly IImportListMovieService _listMovieService; + private readonly IImportExclusionsService _importExclusionService; + + public ImportListMoviesModule(IMovieService movieService, + IProvideMovieInfo movieInfo, + IBuildFileNames fileNameBuilder, + IImportListMovieService listMovieService, + IImportExclusionsService importExclusionsService) + : base("/importlist/movie") + { + _movieService = movieService; + _movieInfo = movieInfo; + _fileNameBuilder = fileNameBuilder; + _listMovieService = listMovieService; + _importExclusionService = importExclusionsService; + Get("/", x => GetDiscoverMovies()); + } + + private object GetDiscoverMovies() + { + var includeRecommendations = Request.GetBooleanQueryParameter("includeRecommendations"); + + var realResults = new List(); + var listExclusions = _importExclusionService.GetAllExclusions(); + var existingTmdbIds = _movieService.AllMovieTmdbIds(); + + if (includeRecommendations) + { + var mapped = new List(); + + var results = _movieService.GetRecommendedTmdbIds(); + + if (results.Count > 0) + { + mapped = _movieInfo.GetBulkMovieInfo(results); + } + + realResults.AddRange(MapToResource(mapped.Where(x => x != null))); + realResults.ForEach(x => x.IsRecommendation = true); + } + + var listMovies = MapToResource(_listMovieService.GetAllListMovies()).ToList(); + + realResults.AddRange(listMovies); + + var groupedListMovies = realResults.GroupBy(x => x.TmdbId); + + // Distinct Movies + realResults = groupedListMovies.Select(x => + { + var movie = x.First(); + + movie.Lists = x.SelectMany(m => m.Lists).ToHashSet(); + movie.IsExcluded = listExclusions.Any(e => e.TmdbId == movie.TmdbId); + movie.IsExisting = existingTmdbIds.Any(e => e == movie.TmdbId); + movie.IsRecommendation = x.Any(m => m.IsRecommendation); + + return movie; + }).ToList(); + + return realResults; + } + + private IEnumerable MapToResource(IEnumerable movies) + { + foreach (var currentMovie in movies) + { + var resource = DiscoverMoviesResourceMapper.ToResource(currentMovie); + var poster = currentMovie.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster); + if (poster != null) + { + resource.RemotePoster = poster.Url; + } + + resource.Folder = _fileNameBuilder.GetMovieFolder(currentMovie); + + yield return resource; + } + } + + private IEnumerable MapToResource(IEnumerable movies) + { + foreach (var currentMovie in movies) + { + var resource = DiscoverMoviesResourceMapper.ToResource(currentMovie); + var poster = currentMovie.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster); + if (poster != null) + { + resource.RemotePoster = poster.Url; + } + + resource.Folder = _fileNameBuilder.GetMovieFolder(new Movie { Title = currentMovie.Title, Year = currentMovie.Year, ImdbId = currentMovie.ImdbId, TmdbId = currentMovie.TmdbId }); + + yield return resource; + } + } + } +} diff --git a/src/Radarr.Api.V3/Movies/DiscoverMoviesResource.cs b/src/Radarr.Api.V3/ImportLists/ImportListMoviesResource.cs similarity index 55% rename from src/Radarr.Api.V3/Movies/DiscoverMoviesResource.cs rename to src/Radarr.Api.V3/ImportLists/ImportListMoviesResource.cs index 96b5080fa..2f8bdf2c2 100644 --- a/src/Radarr.Api.V3/Movies/DiscoverMoviesResource.cs +++ b/src/Radarr.Api.V3/ImportLists/ImportListMoviesResource.cs @@ -1,22 +1,26 @@ using System; using System.Collections.Generic; +using NzbDrone.Core.ImportLists.ImportListMovies; using NzbDrone.Core.MediaCover; using NzbDrone.Core.Movies; -using NzbDrone.Core.NetImport.ImportExclusions; using Radarr.Http.REST; -namespace Radarr.Api.V3.Movies +namespace Radarr.Api.V3.ImportLists { - public class DiscoverMoviesResource : RestResource + public class ImportListMoviesResource : RestResource { - //View Only + public ImportListMoviesResource() + { + Lists = new HashSet(); + } + public string Title { get; set; } public string SortTitle { get; set; } - public string TitleSlug { get; set; } public MovieStatusType Status { get; set; } public string Overview { get; set; } public DateTime? InCinemas { get; set; } public DateTime? PhysicalRelease { get; set; } + public DateTime? DigitalRelease { get; set; } public List Images { get; set; } public string Website { get; set; } public string RemotePoster { get; set; } @@ -34,25 +38,63 @@ namespace Radarr.Api.V3.Movies public MovieCollection Collection { get; set; } public bool IsExcluded { get; set; } public bool IsExisting { get; set; } + + public bool IsRecommendation { get; set; } + public HashSet Lists { get; set; } } public static class DiscoverMoviesResourceMapper { - public static DiscoverMoviesResource ToResource(this Movie model, IMovieService movieService, IImportExclusionsService importExclusionService) + public static ImportListMoviesResource ToResource(this Movie model) + { + if (model == null) + { + return null; + } + + return new ImportListMoviesResource + { + TmdbId = model.TmdbId, + Title = model.Title, + SortTitle = model.SortTitle, + InCinemas = model.InCinemas, + PhysicalRelease = model.PhysicalRelease, + DigitalRelease = model.DigitalRelease, + + Status = model.Status, + Overview = model.Overview, + + Images = model.Images, + + Year = model.Year, + + Runtime = model.Runtime, + ImdbId = model.ImdbId, + Certification = model.Certification, + Website = model.Website, + Genres = model.Genres, + Ratings = model.Ratings, + YouTubeTrailerId = model.YouTubeTrailerId, + Studio = model.Studio, + Collection = model.Collection + }; + } + + public static ImportListMoviesResource ToResource(this ImportListMovie model) { if (model == null) { return null; } - return new DiscoverMoviesResource + return new ImportListMoviesResource { TmdbId = model.TmdbId, Title = model.Title, SortTitle = model.SortTitle, - TitleSlug = model.TitleSlug, InCinemas = model.InCinemas, PhysicalRelease = model.PhysicalRelease, + DigitalRelease = model.DigitalRelease, Status = model.Status, Overview = model.Overview, @@ -70,8 +112,7 @@ namespace Radarr.Api.V3.Movies YouTubeTrailerId = model.YouTubeTrailerId, Studio = model.Studio, Collection = model.Collection, - IsExcluded = importExclusionService.IsMovieExcluded(model.TmdbId), - IsExisting = movieService.FindByTmdbId(model.TmdbId) != null, + Lists = new HashSet { model.ListId } }; } } diff --git a/src/Radarr.Api.V3/NetImport/NetImportResource.cs b/src/Radarr.Api.V3/ImportLists/ImportListResource.cs similarity index 73% rename from src/Radarr.Api.V3/NetImport/NetImportResource.cs rename to src/Radarr.Api.V3/ImportLists/ImportListResource.cs index 85e992c5e..05e3c2aed 100644 --- a/src/Radarr.Api.V3/NetImport/NetImportResource.cs +++ b/src/Radarr.Api.V3/ImportLists/ImportListResource.cs @@ -1,23 +1,24 @@ +using NzbDrone.Core.ImportLists; using NzbDrone.Core.Movies; -using NzbDrone.Core.NetImport; -namespace Radarr.Api.V3.NetImport +namespace Radarr.Api.V3.ImportLists { - public class NetImportResource : ProviderResource + public class ImportListResource : ProviderResource { public bool Enabled { get; set; } public bool EnableAuto { get; set; } public bool ShouldMonitor { get; set; } public string RootFolderPath { get; set; } public int QualityProfileId { get; set; } + public bool SearchOnAdd { get; set; } public MovieStatusType MinimumAvailability { get; set; } - public NetImportType ListType { get; set; } + public ImportListType ListType { get; set; } public int ListOrder { get; set; } } - public class NetImportResourceMapper : ProviderResourceMapper + public class ImportListResourceMapper : ProviderResourceMapper { - public override NetImportResource ToResource(NetImportDefinition definition) + public override ImportListResource ToResource(ImportListDefinition definition) { if (definition == null) { @@ -29,6 +30,7 @@ namespace Radarr.Api.V3.NetImport resource.Enabled = definition.Enabled; resource.EnableAuto = definition.EnableAuto; resource.ShouldMonitor = definition.ShouldMonitor; + resource.SearchOnAdd = definition.SearchOnAdd; resource.RootFolderPath = definition.RootFolderPath; resource.QualityProfileId = definition.ProfileId; resource.MinimumAvailability = definition.MinimumAvailability; @@ -38,7 +40,7 @@ namespace Radarr.Api.V3.NetImport return resource; } - public override NetImportDefinition ToModel(NetImportResource resource) + public override ImportListDefinition ToModel(ImportListResource resource) { if (resource == null) { @@ -50,6 +52,7 @@ namespace Radarr.Api.V3.NetImport definition.Enabled = resource.Enabled; definition.EnableAuto = resource.EnableAuto; definition.ShouldMonitor = resource.ShouldMonitor; + definition.SearchOnAdd = resource.SearchOnAdd; definition.RootFolderPath = resource.RootFolderPath; definition.ProfileId = resource.QualityProfileId; definition.MinimumAvailability = resource.MinimumAvailability; diff --git a/src/Radarr.Api.V3/Movies/DiscoverMoviesModule.cs b/src/Radarr.Api.V3/Movies/DiscoverMoviesModule.cs deleted file mode 100644 index f3d22cb12..000000000 --- a/src/Radarr.Api.V3/Movies/DiscoverMoviesModule.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using NzbDrone.Core.MediaCover; -using NzbDrone.Core.MetadataSource; -using NzbDrone.Core.Movies; -using NzbDrone.Core.NetImport.ImportExclusions; -using NzbDrone.Core.Organizer; -using Radarr.Http; - -namespace Radarr.Api.V3.Movies -{ - public class DiscoverMoviesModule : RadarrRestModule - { - private readonly IMovieService _movieService; - private readonly IProvideMovieInfo _movieInfo; - private readonly IBuildFileNames _fileNameBuilder; - private readonly IImportExclusionsService _importExclusionService; - - public DiscoverMoviesModule(IMovieService movieService, IProvideMovieInfo movieInfo, IBuildFileNames fileNameBuilder, IImportExclusionsService importExclusionsService) - : base("/movies/discover") - { - _movieService = movieService; - _movieInfo = movieInfo; - _fileNameBuilder = fileNameBuilder; - _importExclusionService = importExclusionsService; - Get("/", x => GetDiscoverMovies()); - } - - private object GetDiscoverMovies() - { - var results = _movieService.GetRecommendedMovies(); - - var mapped = new List(); - - if (results.Count > 0) - { - mapped = _movieInfo.GetBulkMovieInfo(results.Select(m => m.TmdbId).ToList()); - } - - var realResults = new List(); - - realResults.AddRange(mapped.Where(x => x != null)); - - return MapToResource(realResults); - } - - private IEnumerable MapToResource(IEnumerable movies) - { - foreach (var currentMovie in movies) - { - var resource = currentMovie.ToResource(_movieService, _importExclusionService); - var poster = currentMovie.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster); - if (poster != null) - { - resource.RemotePoster = poster.Url; - } - - resource.Folder = _fileNameBuilder.GetMovieFolder(currentMovie); - - yield return resource; - } - } - } -} diff --git a/src/Radarr.Api.V3/Movies/FetchMovieListModule.cs b/src/Radarr.Api.V3/Movies/FetchMovieListModule.cs deleted file mode 100644 index 5ee1b15df..000000000 --- a/src/Radarr.Api.V3/Movies/FetchMovieListModule.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Nancy; -using NzbDrone.Common.Extensions; -using NzbDrone.Core.MediaCover; -using NzbDrone.Core.MetadataSource; -using NzbDrone.Core.Movies; -using NzbDrone.Core.NetImport; -using Radarr.Http; - -namespace Radarr.Api.V3.Movies -{ - public class FetchMovieListModule : RadarrRestModule - { - private readonly IFetchNetImport _fetchNetImport; - private readonly ISearchForNewMovie _movieSearch; - private readonly IProvideMovieInfo _movieInfo; - - public FetchMovieListModule(IFetchNetImport netImport, ISearchForNewMovie movieSearch, IProvideMovieInfo movieInfo) - : base("/netimport/movies") - { - _fetchNetImport = netImport; - _movieSearch = movieSearch; - _movieInfo = movieInfo; - Get("/", x => Search()); - } - - private object Search() - { - var results = _fetchNetImport.FetchAndFilter((int)Request.Query.listId, false); - - List realResults = new List(); - - var bulkResults = results.Where(r => r.TmdbId != 0); - - bulkResults = _movieInfo.GetBulkMovieInfo(bulkResults.Select(m => m.TmdbId).ToList()); - - foreach (var movie in results.Where(r => r.TmdbId == 0)) - { - var mapped = movie; - - if (movie.TmdbId == 0 || !movie.Images.Any() || movie.Overview.IsNullOrWhiteSpace()) - { - mapped = _movieSearch.MapMovieToTmdbMovie(movie); - } - - if (mapped != null) - { - realResults.Add(mapped); - } - } - - realResults.AddRange(bulkResults); - - return MapToResource(realResults); - } - - private static IEnumerable MapToResource(IEnumerable movies) - { - foreach (var currentSeries in movies) - { - var resource = currentSeries.ToResource(); - var poster = currentSeries.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster); - if (poster != null) - { - resource.RemotePoster = poster.Url; - } - - yield return resource; - } - } - } -} diff --git a/src/Radarr.Api.V3/Movies/MovieEditorModule.cs b/src/Radarr.Api.V3/Movies/MovieEditorModule.cs index dbf0278b9..776718ff2 100644 --- a/src/Radarr.Api.V3/Movies/MovieEditorModule.cs +++ b/src/Radarr.Api.V3/Movies/MovieEditorModule.cs @@ -94,7 +94,7 @@ namespace Radarr.Api.V3.Movies { var resource = Request.Body.FromJson(); - _movieService.DeleteMovies(resource.MovieIds, resource.DeleteFiles, resource.AddNetImportExclusion); + _movieService.DeleteMovies(resource.MovieIds, resource.DeleteFiles, resource.AddImportExclusion); return new object(); } diff --git a/src/Radarr.Api.V3/Movies/MovieEditorResource.cs b/src/Radarr.Api.V3/Movies/MovieEditorResource.cs index 44ca50b17..e19ffd0e3 100644 --- a/src/Radarr.Api.V3/Movies/MovieEditorResource.cs +++ b/src/Radarr.Api.V3/Movies/MovieEditorResource.cs @@ -14,7 +14,7 @@ namespace Radarr.Api.V3.Movies public ApplyTags ApplyTags { get; set; } public bool MoveFiles { get; set; } public bool DeleteFiles { get; set; } - public bool AddNetImportExclusion { get; set; } + public bool AddImportExclusion { get; set; } } public enum ApplyTags diff --git a/src/Radarr.Api.V3/Movies/MovieModule.cs b/src/Radarr.Api.V3/Movies/MovieModule.cs index 5a9a20526..125e95edb 100644 --- a/src/Radarr.Api.V3/Movies/MovieModule.cs +++ b/src/Radarr.Api.V3/Movies/MovieModule.cs @@ -187,7 +187,7 @@ namespace Radarr.Api.V3.Movies private void DeleteMovie(int id) { - var addExclusion = Request.GetBooleanQueryParameter("addNetImportExclusion"); + var addExclusion = Request.GetBooleanQueryParameter("addImportExclusion"); var deleteFiles = Request.GetBooleanQueryParameter("deleteFiles"); _moviesService.DeleteMovie(id, deleteFiles, addExclusion); diff --git a/src/Radarr.Api.V3/Tags/TagDetailsResource.cs b/src/Radarr.Api.V3/Tags/TagDetailsResource.cs index 2981069f0..1d9dfbf19 100644 --- a/src/Radarr.Api.V3/Tags/TagDetailsResource.cs +++ b/src/Radarr.Api.V3/Tags/TagDetailsResource.cs @@ -11,7 +11,7 @@ namespace Radarr.Api.V3.Tags public List DelayProfileIds { get; set; } public List NotificationIds { get; set; } public List RestrictionIds { get; set; } - public List NetImportIds { get; set; } + public List ImportListIds { get; set; } public List MovieIds { get; set; } } @@ -31,7 +31,7 @@ namespace Radarr.Api.V3.Tags DelayProfileIds = model.DelayProfileIds, NotificationIds = model.NotificationIds, RestrictionIds = model.RestrictionIds, - NetImportIds = model.NetImportIds, + ImportListIds = model.ImportListIds, MovieIds = model.MovieIds }; } diff --git a/src/Radarr.Api.V3/swagger.json b/src/Radarr.Api.V3/swagger.json index 373298e9b..dcf439d14 100644 --- a/src/Radarr.Api.V3/swagger.json +++ b/src/Radarr.Api.V3/swagger.json @@ -198,7 +198,7 @@ } }, { - "name": "addNetImportExclusion", + "name": "addImportExclusion", "in": "query", "schema": { "type": "boolean" diff --git a/src/Radarr.Http/Validation/NetImportSyncIntervalValidator.cs b/src/Radarr.Http/Validation/NetImportSyncIntervalValidator.cs index 5593e4a98..812a1275c 100644 --- a/src/Radarr.Http/Validation/NetImportSyncIntervalValidator.cs +++ b/src/Radarr.Http/Validation/NetImportSyncIntervalValidator.cs @@ -2,9 +2,9 @@ using FluentValidation.Validators; namespace Radarr.Http.Validation { - public class NetImportSyncIntervalValidator : PropertyValidator + public class ImportListSyncIntervalValidator : PropertyValidator { - public NetImportSyncIntervalValidator() + public ImportListSyncIntervalValidator() : base("Must be between 10 and 1440 or 0 to disable") { } diff --git a/src/Radarr.Http/Validation/RuleBuilderExtensions.cs b/src/Radarr.Http/Validation/RuleBuilderExtensions.cs index dcaeb8bf1..4fe1a5c39 100644 --- a/src/Radarr.Http/Validation/RuleBuilderExtensions.cs +++ b/src/Radarr.Http/Validation/RuleBuilderExtensions.cs @@ -37,9 +37,9 @@ namespace Radarr.Http.Validation return ruleBuilder.SetValidator(new RssSyncIntervalValidator()); } - public static IRuleBuilderOptions IsValidNetImportSyncInterval(this IRuleBuilder ruleBuilder) + public static IRuleBuilderOptions IsValidImportListSyncInterval(this IRuleBuilder ruleBuilder) { - return ruleBuilder.SetValidator(new NetImportSyncIntervalValidator()); + return ruleBuilder.SetValidator(new ImportListSyncIntervalValidator()); } } }