From 65efa155513947b35cd5763fa15f5f3226cf4102 Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 23 Nov 2018 02:03:32 -0500 Subject: [PATCH] New: Backend changes for new UI --- .../ClientSchemaTests/SchemaBuilderFixture.cs | 10 +- .../NzbDrone.Api.Test.csproj | 6 +- .../Properties/AssemblyInfo.cs | 4 +- src/NzbDrone.Api/Blacklist/BlacklistModule.cs | 5 +- .../Blacklist/BlacklistResource.cs | 2 +- .../ClientSchema/FieldDefinitionAttribute.cs | 4 - .../ClientSchema/SchemaBuilder.cs | 193 ----------- .../ClientSchema/SchemaDeserializer.cs | 7 - src/NzbDrone.Api/Commands/CommandModule.cs | 12 +- src/NzbDrone.Api/Commands/CommandResource.cs | 2 +- .../Config/DownloadClientConfigModule.cs | 17 +- .../Config/DownloadClientConfigResource.cs | 6 +- src/NzbDrone.Api/Config/HostConfigModule.cs | 10 +- src/NzbDrone.Api/Config/HostConfigResource.cs | 10 +- .../Config/IndexerConfigModule.cs | 2 +- .../Config/IndexerConfigResource.cs | 2 +- .../Config/MediaManagementConfigResource.cs | 6 +- src/NzbDrone.Api/Config/NamingConfigModule.cs | 6 +- .../Config/NamingConfigResource.cs | 2 +- .../Config/NetImportConfigModule.cs | 6 +- .../Config/NetImportConfigResource.cs | 2 +- .../Config/NzbDroneConfigModule.cs | 7 +- src/NzbDrone.Api/Config/UiConfigResource.cs | 2 +- src/NzbDrone.Api/DiskSpace/DiskSpaceModule.cs | 5 +- .../DiskSpace/DiskSpaceResource.cs | 2 +- .../ExtraFiles/ExtraFileModule.cs | 5 +- .../ExtraFiles/ExtraFileResource.cs | 2 +- .../FileSystem/FileSystemModule.cs | 17 +- .../Frontend/Mappers/IndexHtmlMapper.cs | 121 ------- .../Frontend/Mappers/LoginHtmlMapper.cs | 90 ----- src/NzbDrone.Api/Health/HealthModule.cs | 7 +- src/NzbDrone.Api/Health/HealthResource.cs | 2 +- src/NzbDrone.Api/History/HistoryModule.cs | 17 +- src/NzbDrone.Api/History/HistoryResource.cs | 2 +- src/NzbDrone.Api/Indexers/ReleaseModule.cs | 2 +- .../Indexers/ReleaseModuleBase.cs | 5 +- .../Indexers/ReleasePushModule.cs | 5 +- src/NzbDrone.Api/Indexers/ReleaseResource.cs | 2 +- src/NzbDrone.Api/Logs/LogFileModuleBase.cs | 7 +- src/NzbDrone.Api/Logs/LogFileResource.cs | 2 +- src/NzbDrone.Api/Logs/LogModule.cs | 26 +- src/NzbDrone.Api/Logs/LogResource.cs | 2 +- .../ManualImport/ManualImportModule.cs | 9 +- .../ManualImport/ManualImportResource.cs | 2 +- .../MovieFiles/MovieFileModule.cs | 5 +- .../MovieFiles/MovieFileResource.cs | 2 +- .../Movies/AlternativeTitleModule.cs | 3 +- .../Movies/AlternativeTitleResource.cs | 2 +- .../Movies/AlternativeYearModule.cs | 3 +- .../Movies/AlternativeYearResource.cs | 2 +- .../Movies/FetchMovieListModule.cs | 5 +- .../Movies/MovieBulkImportModule.cs | 5 +- .../Movies/MovieDiscoverModule.cs | 6 +- src/NzbDrone.Api/Movies/MovieEditorModule.cs | 5 +- src/NzbDrone.Api/Movies/MovieLookupModule.cs | 7 +- src/NzbDrone.Api/Movies/MovieModule.cs | 17 +- .../Movies/MovieModuleWithSignalR.cs | 3 +- src/NzbDrone.Api/Movies/MovieResource.cs | 2 +- src/NzbDrone.Api/Movies/RenameMovieModule.cs | 5 +- .../Movies/RenameMovieResource.cs | 2 +- .../NetImport/ImportExclusionsModule.cs | 5 +- .../NetImport/ListImportModule.cs | 2 +- src/NzbDrone.Api/NetImport/NetImportModule.cs | 4 +- src/NzbDrone.Api/NzbDrone.Api.csproj | 65 +--- .../NzbDroneRestModuleWithSignalR.cs | 66 ---- src/NzbDrone.Api/Parse/ParseModule.cs | 3 +- src/NzbDrone.Api/Parse/ParseResource.cs | 2 +- .../Profiles/Delay/DelayProfileModule.cs | 11 +- .../Profiles/Delay/DelayProfileResource.cs | 2 +- .../Profiles/Languages/LanguageModule.cs | 7 +- .../Profiles/Languages/LanguageResource.cs | 2 +- src/NzbDrone.Api/Profiles/ProfileModule.cs | 6 +- src/NzbDrone.Api/Profiles/ProfileResource.cs | 6 +- .../Profiles/ProfileSchemaModule.cs | 10 +- src/NzbDrone.Api/Properties/AssemblyInfo.cs | 4 +- src/NzbDrone.Api/ProviderModuleBase.cs | 10 +- src/NzbDrone.Api/ProviderResource.cs | 8 +- .../Qualities/CustomFormatModule.cs | 11 +- .../Qualities/CustomFormatResource.cs | 2 +- .../Qualities/FormatTagMatchResultResource.cs | 2 +- .../Qualities/QualityDefinitionModule.cs | 7 +- .../Qualities/QualityDefinitionResource.cs | 2 +- src/NzbDrone.Api/Queue/QueueActionModule.cs | 9 +- src/NzbDrone.Api/Queue/QueueModule.cs | 7 +- src/NzbDrone.Api/Queue/QueueResource.cs | 2 +- .../RemotePathMappingModule.cs | 7 +- .../RemotePathMappingResource.cs | 2 +- .../Restrictions/RestrictionModule.cs | 7 +- .../Restrictions/RestrictionResource.cs | 4 +- .../RootFolders/RootFolderModule.cs | 12 +- .../RootFolders/RootFolderResource.cs | 2 +- src/NzbDrone.Api/Series/SeriesModule.cs | 47 --- src/NzbDrone.Api/Series/SeriesResource.cs | 19 - .../System/Backup/BackupModule.cs | 5 +- .../System/Backup/BackupResource.cs | 4 +- src/NzbDrone.Api/System/SystemModule.cs | 2 +- src/NzbDrone.Api/System/Tasks/TaskModule.cs | 3 +- src/NzbDrone.Api/System/Tasks/TaskResource.cs | 4 +- src/NzbDrone.Api/Tags/TagModule.cs | 5 +- src/NzbDrone.Api/Tags/TagResource.cs | 4 +- src/NzbDrone.Api/Update/UpdateModule.cs | 7 +- src/NzbDrone.Api/Update/UpdateResource.cs | 4 +- src/NzbDrone.Api/Wanted/MovieCutoffModule.cs | 15 +- src/NzbDrone.Api/Wanted/MovieMissingModule.cs | 23 +- .../NzbDrone.Host.Test.csproj | 10 +- .../NzbDroneProcessServiceFixture.cs | 12 +- .../Properties/AssemblyInfo.cs | 4 +- src/NzbDrone.App.Test/RouterTest.cs | 25 +- .../NzbDrone.Automation.Test.csproj | 2 +- .../Properties/AssemblyInfo.cs | 4 +- .../DirectoryLookupServiceFixture.cs | 8 +- .../EnvironmentInfo/BuildInfoFixture.cs | 22 ++ .../NzbDrone.Common.Test.csproj | 3 +- .../PathExtensionFixture.cs | 4 +- .../ReflectionExtensionFixture.cs | 8 +- .../ServiceProviderTests.cs | 4 +- src/NzbDrone.Common/ArchiveService.cs | 7 +- .../Composition/ContainerBuilderBase.cs | 4 +- src/NzbDrone.Common/ConsoleService.cs | 8 +- src/NzbDrone.Common/Disk/DiskProviderBase.cs | 8 + .../Disk/FileSystemLookupService.cs | 121 ++++--- src/NzbDrone.Common/Disk/IDiskProvider.cs | 3 +- .../EnvironmentInfo/AppFolderFactory.cs | 83 ++++- .../EnvironmentInfo/BuildInfo.cs | 28 +- .../EnvironmentInfo/IRuntimeInfo.cs | 5 + .../EnvironmentInfo/RuntimeInfo.cs | 46 ++- .../EnvironmentInfo/RuntimeMode.cs | 9 + .../Exceptions/RadarrStartupException.cs | 44 +++ .../Extensions/IEnumerableExtensions.cs | 4 +- .../Extensions/PathExtensions.cs | 19 +- .../Extensions/StringExtensions.cs | 12 + .../Extensions/TryParseExtensions.cs | 17 +- .../Http/Dispatchers/CurlHttpDispatcher.cs | 167 +++++---- .../Dispatchers/FallbackHttpDispatcher.cs | 15 +- .../Http/Dispatchers/ManagedHttpDispatcher.cs | 122 +++---- src/NzbDrone.Common/Http/HttpClient.cs | 50 ++- src/NzbDrone.Common/Http/HttpException.cs | 12 +- .../Http/TlsFailureException.cs | 18 + .../Http/UnexpectedHtmlContentException.cs | 13 + src/NzbDrone.Common/NzbDrone.Common.csproj | 6 +- .../Processes/PidFileProvider.cs | 7 +- .../Processes/ProcessProvider.cs | 4 +- .../Properties/AssemblyInfo.cs | 2 +- .../Reflection/ReflectionExtensions.cs | 2 +- src/NzbDrone.Common/ServiceProvider.cs | 2 +- src/NzbDrone.Console/ConsoleApp.cs | 29 +- .../Properties/AssemblyInfo.cs | 2 +- .../DiskSpace/DiskSpaceServiceFixture.cs | 30 -- .../CompletedDownloadServiceFixture.cs | 14 - .../PneumaticProviderFixture.cs | 9 +- .../Checks/DroneFactoryCheckFixture.cs | 54 --- .../Checks/ImportMechanismCheckFixture.cs | 17 +- .../Checks/MonoVersionCheckFixture.cs | 10 +- ...DownloadedEpisodesCommandServiceFixture.cs | 29 +- .../DownloadedMoviesCommandServiceFixture.cs | 36 +- .../UpdateMovieFileQualityServiceFixture.cs | 4 +- .../Commands/CommandQueueManagerFixture.cs | 7 +- .../NzbDrone.Core.Test.csproj | 4 +- .../Properties/AssemblyInfo.cs | 6 +- .../RootFolderServiceFixture.cs | 16 +- .../UpdateTests/UpdateServiceFixture.cs | 6 +- .../SystemFolderValidatorFixture.cs | 74 ++++ .../Annotations/FieldDefinitionAttribute.cs | 10 +- src/NzbDrone.Core/Backup/BackupService.cs | 102 +++++- .../Backup/RestoreBackupFailedException.cs | 18 + .../Configuration/ConfigService.cs | 47 +-- .../Configuration/IConfigService.cs | 13 +- .../Configuration/RescanAfterRefreshType.cs | 9 + .../CustomFilters/CustomFilter.cs | 11 + .../CustomFilters/CustomFilterRepository.cs | 17 + .../CustomFilters/CustomFilterService.cs | 49 +++ .../Datastore/BasicRepository.cs | 19 +- .../Datastore/ConnectionStringFactory.cs | 6 +- .../Datastore/DatabaseRestorationService.cs | 56 +++ src/NzbDrone.Core/Datastore/DbFactory.cs | 91 +++-- .../Migration/152_add_custom_filters.cs | 17 + src/NzbDrone.Core/Datastore/PagingSpec.cs | 9 +- src/NzbDrone.Core/Datastore/TableMapping.cs | 13 +- .../DiskSpace/DiskSpaceService.cs | 16 +- .../CheckForFinishedDownloadCommand.cs | 4 +- .../Download/Clients/Pneumatic/Pneumatic.cs | 16 +- .../rTorrent/RTorrentDirectoryValidator.cs | 4 +- .../Download/CompletedDownloadService.cs | 10 +- .../Download/Pending/PendingReleaseService.cs | 3 +- .../DownloadMonitoringService.cs | 11 +- .../TrackedDownloads/TrackedDownload.cs | 2 + .../TrackedDownloadService.cs | 71 +++- .../TrackedDownloadsRemovedEvent.cs | 15 + .../HealthCheck/Checks/DroneFactoryCheck.cs | 42 --- .../Checks/ImportMechanismCheck.cs | 24 +- .../History/HistoryRepository.cs | 30 +- src/NzbDrone.Core/History/HistoryService.cs | 12 +- .../IndexerSearch/MoviesSearchService.cs | 22 +- .../Indexers/AwesomeHD/AwesomeHDSettings.cs | 4 +- .../Indexers/HDBits/HDBitsSettings.cs | 4 +- .../Indexers/IPTorrents/IPTorrentsSettings.cs | 4 +- .../Indexers/Nyaa/NyaaSettings.cs | 2 +- .../PassThePopcorn/PassThePopcornSettings.cs | 2 +- .../Indexers/Rarbg/RarbgSettings.cs | 4 +- .../TorrentPotato/TorrentPotatoSettings.cs | 2 +- .../TorrentRss/TorrentRssIndexerSettings.cs | 4 +- .../Indexers/Torznab/TorznabSettings.cs | 4 +- src/NzbDrone.Core/Jobs/ScheduledTask.cs | 4 +- src/NzbDrone.Core/Jobs/TaskManager.cs | 28 +- .../Lifecycle/LifecycleService.cs | 4 +- .../MediaFiles/Commands/RenameFilesCommand.cs | 1 + .../MediaFiles/Commands/RenameMovieCommand.cs | 3 +- .../MediaFiles/DiskScanService.cs | 22 +- .../DownloadedMovieCommandService.cs | 31 +- .../MediaFiles/MediaFileService.cs | 6 + .../MovieImport/Manual/ManualImportCommand.cs | 3 +- .../MovieImport/Manual/ManualImportService.cs | 8 +- .../UpdateMovieFileQualityService.cs | 4 +- .../Messaging/Commands/Command.cs | 19 +- .../Messaging/Commands/CommandQueue.cs | 160 ++++++--- .../Messaging/Commands/CommandQueueManager.cs | 121 ++++--- .../Movies/Commands/MoveMovieCommand.cs | 2 + .../Movies/Commands/RefreshMovieCommand.cs | 8 +- .../Movies/Events/MoviesImportedEvent.cs | 15 + src/NzbDrone.Core/Movies/MovieAddedHandler.cs | 12 +- src/NzbDrone.Core/Movies/MovieRepository.cs | 5 +- src/NzbDrone.Core/Movies/MovieService.cs | 14 +- .../Movies/RefreshMovieService.cs | 90 +++-- .../Notifications/NotificationDefinition.cs | 7 - .../Notifications/NotificationService.cs | 12 +- .../Notifications/Twitter/TwitterSettings.cs | 6 +- src/NzbDrone.Core/NzbDrone.Core.csproj | 21 +- .../Profiles/Delay/DelayProfileService.cs | 9 +- src/NzbDrone.Core/Properties/AssemblyInfo.cs | 4 +- .../Queue/EstimatedCompletionTimeComparer.cs | 38 ++ src/NzbDrone.Core/Queue/Queue.cs | 3 + src/NzbDrone.Core/Queue/QueueService.cs | 5 +- src/NzbDrone.Core/Queue/TimeleftComparer.cs | 38 ++ ...Core.dll.config => Radarr.Core.dll.config} | 0 .../Restrictions/RestrictionService.cs | 4 +- .../RootFolders/RootFolderService.cs | 5 - src/NzbDrone.Core/Tags/TagDetails.cs | 14 + src/NzbDrone.Core/Tags/TagService.cs | 75 +++- .../ThingiProvider/IProviderFactory.cs | 5 +- .../ThingiProvider/ProviderDefinition.cs | 9 +- .../ThingiProvider/ProviderFactory.cs | 10 +- .../Commands/ApplicationUpdateCommand.cs | 3 +- .../Update/InstallUpdateService.cs | 2 +- .../Validation/Paths/DroneFactoryValidator.cs | 28 -- .../Paths/MovieAncestorValidator.cs | 2 +- .../Validation/Paths/SystemFolderValidator.cs | 91 +++++ src/NzbDrone.Host/Bootstrap.cs | 6 + src/NzbDrone.Host/MainAppContainerBuilder.cs | 12 +- src/NzbDrone.Host/NzbDrone.Host.csproj | 8 + .../Owin/MiddleWare/SignalRMiddleWare.cs | 4 +- src/NzbDrone.Host/Router.cs | 10 +- src/NzbDrone.Host/SingleInstancePolicy.cs | 4 +- .../Client/ClientBase.cs | 7 +- src/NzbDrone.Integration.Test/CorsFixture.cs | 2 +- .../IntegrationTest.cs | 3 +- .../NzbDrone.Integration.Test.csproj | 14 +- .../Properties/AssemblyInfo.cs | 4 +- .../NzbDrone.Libraries.Test.csproj | 2 +- .../Properties/AssemblyInfo.cs | 4 +- .../NzbDrone.Mono.Test.csproj | 2 +- .../Properties/AssemblyInfo.cs | 4 +- src/NzbDrone.Mono/NzbDrone.Mono.csproj | 2 +- src/NzbDrone.Mono/Properties/AssemblyInfo.cs | 4 +- src/NzbDrone.SignalR/NzbDrone.SignalR.csproj | 2 +- .../NzbDronePersistentConnection.cs | 45 ++- .../Properties/AssemblyInfo.cs | 2 +- src/NzbDrone.SignalR/SignalRJsonSerializer.cs | 2 +- src/NzbDrone.SignalR/SignalRMessage.cs | 6 + .../SignalrDependencyResolver.cs | 4 +- .../SonarrPerformanceCounterManager.cs | 6 +- src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs | 4 +- .../NzbDrone.Test.Common.csproj | 6 +- src/NzbDrone.Test.Common/NzbDroneRunner.cs | 23 +- .../Properties/AssemblyInfo.cs | 4 +- src/NzbDrone.Test.Common/TestValidator.cs | 15 + src/NzbDrone.Test.Common/packages.config | 1 + src/NzbDrone.Test.Dummy/DummyApp.cs | 2 +- .../NzbDrone.Test.Dummy.csproj | 2 +- .../Properties/AssemblyInfo.cs | 4 +- .../NzbDrone.Update.Test.csproj | 2 +- src/NzbDrone.Update.Test/ProgramFixture.cs | 4 +- .../Properties/AssemblyInfo.cs | 4 +- .../StartNzbDroneService.cs | 4 +- .../UpdateProviderStartFixture.cs | 2 +- src/NzbDrone.Update/NzbDrone.Update.csproj | 4 +- .../Properties/AssemblyInfo.cs | 2 +- .../UpdateEngine/BackupAppData.cs | 4 +- .../UpdateEngine/DetectApplicationType.cs | 6 +- .../UpdateEngine/InstallUpdateService.cs | 10 +- .../UpdateEngine/StartNzbDrone.cs | 8 +- .../UpdateEngine/TerminateNzbDrone.cs | 14 +- .../NzbDrone.Windows.Test.csproj | 2 +- .../Properties/AssemblyInfo.cs | 4 +- src/NzbDrone.Windows/NzbDrone.Windows.csproj | 2 +- .../Properties/AssemblyInfo.cs | 4 +- .../Blacklist/BlacklistModule.cs | 36 ++ .../Blacklist/BlacklistResource.cs | 45 +++ .../Calendar/CalendarFeedModule.cs | 135 +++++++ src/Radarr.Api.V2/Calendar/CalendarModule.cs | 53 +++ src/Radarr.Api.V2/Commands/CommandModule.cs | 107 ++++++ src/Radarr.Api.V2/Commands/CommandResource.cs | 102 ++++++ .../Config/DownloadClientConfigModule.cs | 20 ++ .../Config/DownloadClientConfigResource.cs | 35 ++ src/Radarr.Api.V2/Config/HostConfigModule.cs | 92 +++++ .../Config/HostConfigResource.cs | 79 +++++ .../Config/IndexerConfigModule.cs | 31 ++ .../Config/IndexerConfigResource.cs | 38 ++ .../Config/MediaManagementConfigModule.cs | 22 ++ .../Config/MediaManagementConfigResource.cs | 62 ++++ .../Config/NamingConfigModule.cs | 109 ++++++ .../Config/NamingConfigResource.cs | 21 ++ .../Config/NamingExampleResource.cs | 67 ++++ .../Config/NetImportConfigModule.cs | 22 ++ .../Config/NetImportConfigResource.cs | 31 ++ .../Config/RadarrConfigModule.cs | 52 +++ src/Radarr.Api.V2/Config/UiConfigModule.cs | 18 + src/Radarr.Api.V2/Config/UiConfigResource.cs | 39 +++ .../CustomFilters/CustomFilterModule.cs | 49 +++ .../CustomFilters/CustomFilterResource.cs | 49 +++ .../DiskSpace/DiskSpaceModule.cs | 23 ++ .../DiskSpace/DiskSpaceResource.cs | 28 ++ .../DownloadClient/DownloadClientModule.cs | 20 ++ .../DownloadClient/DownloadClientResource.cs | 38 ++ .../FileSystem/FileSystemModule.cs | 71 ++++ src/Radarr.Api.V2/Health/HealthModule.cs | 32 ++ src/Radarr.Api.V2/Health/HealthResource.cs | 38 ++ src/Radarr.Api.V2/History/HistoryModule.cs | 120 +++++++ src/Radarr.Api.V2/History/HistoryResource.cs | 49 +++ src/Radarr.Api.V2/Indexers/IndexerModule.cs | 20 ++ src/Radarr.Api.V2/Indexers/IndexerResource.cs | 43 +++ src/Radarr.Api.V2/Indexers/ReleaseModule.cs | 129 +++++++ .../Indexers/ReleaseModuleBase.cs | 42 +++ .../Indexers/ReleasePushModule.cs | 50 +++ src/Radarr.Api.V2/Indexers/ReleaseResource.cs | 137 ++++++++ src/Radarr.Api.V2/Logs/LogFileModule.cs | 43 +++ src/Radarr.Api.V2/Logs/LogFileModuleBase.cs | 72 ++++ src/Radarr.Api.V2/Logs/LogFileResource.cs | 13 + src/Radarr.Api.V2/Logs/LogModule.cs | 63 ++++ src/Radarr.Api.V2/Logs/LogResource.cs | 36 ++ src/Radarr.Api.V2/Logs/UpdateLogFileModule.cs | 48 +++ src/Radarr.Api.V2/Metadata/MetadataModule.cs | 20 ++ .../Metadata/MetadataResource.cs | 34 ++ .../MovieFiles/MediaInfoResource.cs | 67 ++++ .../MovieFiles/MovieFileListResource.cs | 11 + .../MovieFiles/MovieFileModule.cs | 166 +++++++++ .../MovieFiles/MovieFileResource.cs | 87 +++++ .../Movies/AlternativeTitleModule.cs | 57 +++ .../Movies/AlternativeTitleResource.cs | 80 +++++ .../Movies/AlternativeYearModule.cs | 63 ++++ .../Movies/AlternativeYearResource.cs | 74 ++++ .../Movies/FetchMovieListModule.cs | 62 ++++ .../Movies/MovieDiscoverModule.cs | 64 ++++ src/Radarr.Api.V2/Movies/MovieEditorModule.cs | 64 ++++ src/Radarr.Api.V2/Movies/MovieImportModule.cs | 29 ++ src/Radarr.Api.V2/Movies/MovieLookupModule.cs | 69 ++++ src/Radarr.Api.V2/Movies/MovieModule.cs | 196 +++++++++++ src/Radarr.Api.V2/Movies/MovieResource.cs | 240 +++++++++++++ src/Radarr.Api.V2/Movies/RenameMovieModule.cs | 36 ++ .../Movies/RenameMovieResource.cs | 36 ++ .../NetImport/ImportExclusionsModule.cs | 46 +++ .../NetImport/ImportExclusionsResource.cs | 46 +++ .../NetImport/ListImportModule.cs | 34 ++ .../NetImport/NetImportModule.cs | 26 ++ .../NetImport/NetImportResource.cs | 54 +++ .../Notifications/NotificationModule.cs | 20 ++ .../Notifications/NotificationResource.cs | 57 +++ .../Profiles/Delay/DelayProfileModule.cs | 76 ++++ .../Profiles/Delay/DelayProfileResource.cs | 63 ++++ .../Profiles/Languages/LanguageModule.cs | 40 +++ .../Profiles/Languages/LanguageResource.cs | 13 + .../Profiles/Quality/QualityProfileModule.cs | 73 ++++ .../Quality/QualityProfileResource.cs | 117 +++++++ .../Quality/QualityProfileSchemaModule.cs | 54 +++ .../Quality/QualityProfileValidation.cs | 43 +++ src/Radarr.Api.V2/Properties/AssemblyInfo.cs | 9 + src/Radarr.Api.V2/ProviderModuleBase.cs | 210 +++++++++++ src/Radarr.Api.V2/ProviderResource.cs | 70 ++++ src/Radarr.Api.V2/ProviderTestAllResult.cs | 18 + .../Qualities/CustomFormatModule.cs | 133 +++++++ .../Qualities/CustomFormatResource.cs | 42 +++ .../Qualities/FormatTagMatchResultResource.cs | 63 ++++ .../Qualities/FormatTagValidator.cs | 42 +++ .../Qualities/QualityDefinitionModule.cs | 51 +++ .../Qualities/QualityDefinitionResource.cs | 65 ++++ src/Radarr.Api.V2/Queue/QueueActionModule.cs | 167 +++++++++ src/Radarr.Api.V2/Queue/QueueBulkResource.cs | 9 + src/Radarr.Api.V2/Queue/QueueDetailsModule.cs | 55 +++ src/Radarr.Api.V2/Queue/QueueModule.cs | 127 +++++++ src/Radarr.Api.V2/Queue/QueueResource.cs | 65 ++++ src/Radarr.Api.V2/Queue/QueueStatusModule.cs | 74 ++++ .../Queue/QueueStatusResource.cs | 11 + src/Radarr.Api.V2/Radarr.Api.V2.csproj | 231 ++++++++++++ src/Radarr.Api.V2/RadarrV2FeedModule.cs | 12 + src/Radarr.Api.V2/RadarrV2Module.cs | 12 + .../RemotePathMappingModule.cs | 68 ++++ .../RemotePathMappingResource.cs | 50 +++ .../Restrictions/RestrictionModule.cs | 60 ++++ .../Restrictions/RestrictionResource.cs | 58 ++++ .../RootFolders/RootFolderModule.cs | 65 ++++ .../RootFolders/RootFolderResource.cs | 51 +++ .../System/Backup/BackupModule.cs | 33 ++ .../System/Backup/BackupResource.cs | 14 + src/Radarr.Api.V2/System/SystemModule.cs | 95 +++++ src/Radarr.Api.V2/System/Tasks/TaskModule.cs | 66 ++++ .../System/Tasks/TaskResource.cs | 14 + src/Radarr.Api.V2/Tags/TagDetailsModule.cs | 30 ++ src/Radarr.Api.V2/Tags/TagDetailsResource.cs | 39 +++ src/Radarr.Api.V2/Tags/TagModule.cs | 57 +++ src/Radarr.Api.V2/Tags/TagResource.cs | 42 +++ src/Radarr.Api.V2/Update/UpdateModule.cs | 46 +++ src/Radarr.Api.V2/Update/UpdateResource.cs | 53 +++ src/Radarr.Api.V2/app.config | 23 ++ src/Radarr.Api.V2/packages.config | 10 + .../Authentication/1tews5g3.gd1~ | 0 .../Authentication/AuthenticationModule.cs | 5 +- .../Authentication/AuthenticationService.cs | 6 +- .../Authentication/EnableAuthInNancy.cs | 66 +++- .../Authentication/LoginResource.cs | 2 +- .../Authentication/NzbDroneUser.cs | 2 +- .../ClientSchema/Field.cs | 13 +- src/Radarr.Http/ClientSchema/FieldMapping.cs | 12 + src/Radarr.Http/ClientSchema/SchemaBuilder.cs | 221 ++++++++++++ .../ClientSchema/SelectOption.cs | 2 +- .../ErrorManagement/ErrorHandler.cs | 4 +- .../ErrorManagement/ErrorModel.cs | 4 +- .../ErrorManagement/RadarrErrorPipeline.cs} | 27 +- .../Exceptions}/ApiException.cs | 5 +- .../Exceptions/InvalidApiKeyException.cs | 2 +- .../Extensions/AccessControlHeaders.cs | 2 +- .../Extensions/NancyJsonSerializer.cs | 2 +- .../Pipelines/CacheHeaderPipeline.cs | 4 +- .../Extensions/Pipelines/CorsPipeline.cs | 6 +- .../Extensions/Pipelines/GZipPipeline.cs | 8 +- .../Pipelines/IRegisterNancyPipeline.cs | 2 +- .../Pipelines/IfModifiedPipeline.cs | 4 +- .../Pipelines/RadarrVersionPipeline.cs} | 8 +- .../Pipelines/RequestLoggingPipeline.cs | 177 +++++----- .../Extensions/Pipelines/UrlBasePipeline.cs | 6 +- .../Extensions/ReqResExtensions.cs | 2 +- .../Extensions/RequestExtensions.cs | 16 +- .../Frontend/CacheableSpecification.cs | 5 +- .../Frontend/InitializeJsModule.cs | 75 ++++ .../Frontend/Mappers/BackupFileMapper.cs | 15 +- .../Frontend/Mappers/BrowserConfig.cs | 34 ++ .../Frontend/Mappers/CacheBreakerProvider.cs | 2 +- .../Frontend/Mappers/FaviconMapper.cs | 6 +- .../Frontend/Mappers/HtmlMapperBase.cs | 82 +++++ .../Mappers/IMapHttpRequestsToDisk.cs | 2 +- .../Frontend/Mappers/IndexHtmlMapper.cs | 42 +++ .../Frontend/Mappers/LogFileMapper.cs | 2 +- .../Frontend/Mappers/LoginHtmlMapper.cs | 34 ++ .../Frontend/Mappers/ManifestMapper.cs | 34 ++ .../Frontend/Mappers/MediaCoverMapper.cs | 2 +- .../Frontend/Mappers/RobotsTxtMapper.cs | 2 +- .../Frontend/Mappers/StaticResourceMapper.cs | 10 +- .../Mappers/StaticResourceMapperBase.cs | 14 +- .../Frontend/Mappers/UpdateLogFileMapper.cs | 2 +- .../Frontend/StaticResourceModule.cs | 13 +- src/Radarr.Http/Mapping/MappingValidation.cs | 54 +++ .../Mapping/ResourceMappingException.cs | 15 + .../PagingResource.cs | 17 +- src/Radarr.Http/PagingResourceFilter.cs | 8 + src/Radarr.Http/Properties/AssemblyInfo.cs | 36 ++ .../REST/BadRequestException.cs | 4 +- .../REST/MethodNotAllowedException.cs | 4 +- .../REST/NotFoundException.cs | 4 +- .../REST/ResourceValidator.cs | 6 +- .../REST/RestModule.cs | 68 +++- .../REST/RestResource.cs | 2 +- .../REST/UnsupportedMediaTypeException.cs | 13 + src/Radarr.Http/Radarr.Http.csproj | 154 ++++++++ .../RadarrBootstrapper.cs} | 10 +- .../RadarrRestModule.cs} | 36 +- .../RadarrRestModuleWithSignalR.cs | 79 +++++ .../ResourceChangeMessage.cs | 4 +- .../TinyIoCNancyBootstrapper.cs | 4 +- .../Validation/EmptyCollectionValidator.cs | 2 +- .../NetImportSyncIntervalValidator.cs | 4 +- .../Validation/RssSyncIntervalValidator.cs | 6 +- .../Validation/RuleBuilderExtensions.cs | 11 +- src/Radarr.Http/app.config | 19 + src/Radarr.Http/packages.config | 9 + src/Radarr.sln | 328 ++++++++++++++++++ .../ServiceInstall/ServiceHelper.cs | 8 +- .../ServiceUninstall/ServiceHelper.cs | 8 +- 485 files changed, 11162 insertions(+), 2218 deletions(-) delete mode 100644 src/NzbDrone.Api/ClientSchema/FieldDefinitionAttribute.cs delete mode 100644 src/NzbDrone.Api/ClientSchema/SchemaBuilder.cs delete mode 100644 src/NzbDrone.Api/ClientSchema/SchemaDeserializer.cs delete mode 100644 src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs delete mode 100644 src/NzbDrone.Api/Frontend/Mappers/LoginHtmlMapper.cs delete mode 100644 src/NzbDrone.Api/NzbDroneRestModuleWithSignalR.cs delete mode 100644 src/NzbDrone.Api/Series/SeriesModule.cs delete mode 100644 src/NzbDrone.Api/Series/SeriesResource.cs create mode 100644 src/NzbDrone.Common.Test/EnvironmentInfo/BuildInfoFixture.cs create mode 100644 src/NzbDrone.Common/EnvironmentInfo/RuntimeMode.cs create mode 100644 src/NzbDrone.Common/Exceptions/RadarrStartupException.cs create mode 100644 src/NzbDrone.Common/Http/TlsFailureException.cs create mode 100644 src/NzbDrone.Common/Http/UnexpectedHtmlContentException.cs delete mode 100644 src/NzbDrone.Core.Test/HealthCheck/Checks/DroneFactoryCheckFixture.cs create mode 100644 src/NzbDrone.Core.Test/ValidationTests/SystemFolderValidatorFixture.cs create mode 100644 src/NzbDrone.Core/Backup/RestoreBackupFailedException.cs create mode 100644 src/NzbDrone.Core/Configuration/RescanAfterRefreshType.cs create mode 100644 src/NzbDrone.Core/CustomFilters/CustomFilter.cs create mode 100644 src/NzbDrone.Core/CustomFilters/CustomFilterRepository.cs create mode 100644 src/NzbDrone.Core/CustomFilters/CustomFilterService.cs create mode 100644 src/NzbDrone.Core/Datastore/DatabaseRestorationService.cs create mode 100644 src/NzbDrone.Core/Datastore/Migration/152_add_custom_filters.cs create mode 100644 src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadsRemovedEvent.cs delete mode 100644 src/NzbDrone.Core/HealthCheck/Checks/DroneFactoryCheck.cs create mode 100644 src/NzbDrone.Core/Movies/Events/MoviesImportedEvent.cs create mode 100644 src/NzbDrone.Core/Queue/EstimatedCompletionTimeComparer.cs create mode 100644 src/NzbDrone.Core/Queue/TimeleftComparer.cs rename src/NzbDrone.Core/{NzbDrone.Core.dll.config => Radarr.Core.dll.config} (100%) create mode 100644 src/NzbDrone.Core/Tags/TagDetails.cs delete mode 100644 src/NzbDrone.Core/Validation/Paths/DroneFactoryValidator.cs create mode 100644 src/NzbDrone.Core/Validation/Paths/SystemFolderValidator.cs create mode 100644 src/NzbDrone.Test.Common/TestValidator.cs create mode 100644 src/Radarr.Api.V2/Blacklist/BlacklistModule.cs create mode 100644 src/Radarr.Api.V2/Blacklist/BlacklistResource.cs create mode 100644 src/Radarr.Api.V2/Calendar/CalendarFeedModule.cs create mode 100644 src/Radarr.Api.V2/Calendar/CalendarModule.cs create mode 100644 src/Radarr.Api.V2/Commands/CommandModule.cs create mode 100644 src/Radarr.Api.V2/Commands/CommandResource.cs create mode 100644 src/Radarr.Api.V2/Config/DownloadClientConfigModule.cs create mode 100644 src/Radarr.Api.V2/Config/DownloadClientConfigResource.cs create mode 100644 src/Radarr.Api.V2/Config/HostConfigModule.cs create mode 100644 src/Radarr.Api.V2/Config/HostConfigResource.cs create mode 100644 src/Radarr.Api.V2/Config/IndexerConfigModule.cs create mode 100644 src/Radarr.Api.V2/Config/IndexerConfigResource.cs create mode 100644 src/Radarr.Api.V2/Config/MediaManagementConfigModule.cs create mode 100644 src/Radarr.Api.V2/Config/MediaManagementConfigResource.cs create mode 100644 src/Radarr.Api.V2/Config/NamingConfigModule.cs create mode 100644 src/Radarr.Api.V2/Config/NamingConfigResource.cs create mode 100644 src/Radarr.Api.V2/Config/NamingExampleResource.cs create mode 100644 src/Radarr.Api.V2/Config/NetImportConfigModule.cs create mode 100644 src/Radarr.Api.V2/Config/NetImportConfigResource.cs create mode 100644 src/Radarr.Api.V2/Config/RadarrConfigModule.cs create mode 100644 src/Radarr.Api.V2/Config/UiConfigModule.cs create mode 100644 src/Radarr.Api.V2/Config/UiConfigResource.cs create mode 100644 src/Radarr.Api.V2/CustomFilters/CustomFilterModule.cs create mode 100644 src/Radarr.Api.V2/CustomFilters/CustomFilterResource.cs create mode 100644 src/Radarr.Api.V2/DiskSpace/DiskSpaceModule.cs create mode 100644 src/Radarr.Api.V2/DiskSpace/DiskSpaceResource.cs create mode 100644 src/Radarr.Api.V2/DownloadClient/DownloadClientModule.cs create mode 100644 src/Radarr.Api.V2/DownloadClient/DownloadClientResource.cs create mode 100644 src/Radarr.Api.V2/FileSystem/FileSystemModule.cs create mode 100644 src/Radarr.Api.V2/Health/HealthModule.cs create mode 100644 src/Radarr.Api.V2/Health/HealthResource.cs create mode 100644 src/Radarr.Api.V2/History/HistoryModule.cs create mode 100644 src/Radarr.Api.V2/History/HistoryResource.cs create mode 100644 src/Radarr.Api.V2/Indexers/IndexerModule.cs create mode 100644 src/Radarr.Api.V2/Indexers/IndexerResource.cs create mode 100644 src/Radarr.Api.V2/Indexers/ReleaseModule.cs create mode 100644 src/Radarr.Api.V2/Indexers/ReleaseModuleBase.cs create mode 100644 src/Radarr.Api.V2/Indexers/ReleasePushModule.cs create mode 100644 src/Radarr.Api.V2/Indexers/ReleaseResource.cs create mode 100644 src/Radarr.Api.V2/Logs/LogFileModule.cs create mode 100644 src/Radarr.Api.V2/Logs/LogFileModuleBase.cs create mode 100644 src/Radarr.Api.V2/Logs/LogFileResource.cs create mode 100644 src/Radarr.Api.V2/Logs/LogModule.cs create mode 100644 src/Radarr.Api.V2/Logs/LogResource.cs create mode 100644 src/Radarr.Api.V2/Logs/UpdateLogFileModule.cs create mode 100644 src/Radarr.Api.V2/Metadata/MetadataModule.cs create mode 100644 src/Radarr.Api.V2/Metadata/MetadataResource.cs create mode 100644 src/Radarr.Api.V2/MovieFiles/MediaInfoResource.cs create mode 100644 src/Radarr.Api.V2/MovieFiles/MovieFileListResource.cs create mode 100644 src/Radarr.Api.V2/MovieFiles/MovieFileModule.cs create mode 100644 src/Radarr.Api.V2/MovieFiles/MovieFileResource.cs create mode 100644 src/Radarr.Api.V2/Movies/AlternativeTitleModule.cs create mode 100644 src/Radarr.Api.V2/Movies/AlternativeTitleResource.cs create mode 100644 src/Radarr.Api.V2/Movies/AlternativeYearModule.cs create mode 100644 src/Radarr.Api.V2/Movies/AlternativeYearResource.cs create mode 100644 src/Radarr.Api.V2/Movies/FetchMovieListModule.cs create mode 100644 src/Radarr.Api.V2/Movies/MovieDiscoverModule.cs create mode 100644 src/Radarr.Api.V2/Movies/MovieEditorModule.cs create mode 100644 src/Radarr.Api.V2/Movies/MovieImportModule.cs create mode 100644 src/Radarr.Api.V2/Movies/MovieLookupModule.cs create mode 100644 src/Radarr.Api.V2/Movies/MovieModule.cs create mode 100644 src/Radarr.Api.V2/Movies/MovieResource.cs create mode 100644 src/Radarr.Api.V2/Movies/RenameMovieModule.cs create mode 100644 src/Radarr.Api.V2/Movies/RenameMovieResource.cs create mode 100644 src/Radarr.Api.V2/NetImport/ImportExclusionsModule.cs create mode 100644 src/Radarr.Api.V2/NetImport/ImportExclusionsResource.cs create mode 100644 src/Radarr.Api.V2/NetImport/ListImportModule.cs create mode 100644 src/Radarr.Api.V2/NetImport/NetImportModule.cs create mode 100644 src/Radarr.Api.V2/NetImport/NetImportResource.cs create mode 100644 src/Radarr.Api.V2/Notifications/NotificationModule.cs create mode 100644 src/Radarr.Api.V2/Notifications/NotificationResource.cs create mode 100644 src/Radarr.Api.V2/Profiles/Delay/DelayProfileModule.cs create mode 100644 src/Radarr.Api.V2/Profiles/Delay/DelayProfileResource.cs create mode 100644 src/Radarr.Api.V2/Profiles/Languages/LanguageModule.cs create mode 100644 src/Radarr.Api.V2/Profiles/Languages/LanguageResource.cs create mode 100644 src/Radarr.Api.V2/Profiles/Quality/QualityProfileModule.cs create mode 100644 src/Radarr.Api.V2/Profiles/Quality/QualityProfileResource.cs create mode 100644 src/Radarr.Api.V2/Profiles/Quality/QualityProfileSchemaModule.cs create mode 100644 src/Radarr.Api.V2/Profiles/Quality/QualityProfileValidation.cs create mode 100644 src/Radarr.Api.V2/Properties/AssemblyInfo.cs create mode 100644 src/Radarr.Api.V2/ProviderModuleBase.cs create mode 100644 src/Radarr.Api.V2/ProviderResource.cs create mode 100644 src/Radarr.Api.V2/ProviderTestAllResult.cs create mode 100644 src/Radarr.Api.V2/Qualities/CustomFormatModule.cs create mode 100644 src/Radarr.Api.V2/Qualities/CustomFormatResource.cs create mode 100644 src/Radarr.Api.V2/Qualities/FormatTagMatchResultResource.cs create mode 100644 src/Radarr.Api.V2/Qualities/FormatTagValidator.cs create mode 100644 src/Radarr.Api.V2/Qualities/QualityDefinitionModule.cs create mode 100644 src/Radarr.Api.V2/Qualities/QualityDefinitionResource.cs create mode 100644 src/Radarr.Api.V2/Queue/QueueActionModule.cs create mode 100644 src/Radarr.Api.V2/Queue/QueueBulkResource.cs create mode 100644 src/Radarr.Api.V2/Queue/QueueDetailsModule.cs create mode 100644 src/Radarr.Api.V2/Queue/QueueModule.cs create mode 100644 src/Radarr.Api.V2/Queue/QueueResource.cs create mode 100644 src/Radarr.Api.V2/Queue/QueueStatusModule.cs create mode 100644 src/Radarr.Api.V2/Queue/QueueStatusResource.cs create mode 100644 src/Radarr.Api.V2/Radarr.Api.V2.csproj create mode 100644 src/Radarr.Api.V2/RadarrV2FeedModule.cs create mode 100644 src/Radarr.Api.V2/RadarrV2Module.cs create mode 100644 src/Radarr.Api.V2/RemotePathMappings/RemotePathMappingModule.cs create mode 100644 src/Radarr.Api.V2/RemotePathMappings/RemotePathMappingResource.cs create mode 100644 src/Radarr.Api.V2/Restrictions/RestrictionModule.cs create mode 100644 src/Radarr.Api.V2/Restrictions/RestrictionResource.cs create mode 100644 src/Radarr.Api.V2/RootFolders/RootFolderModule.cs create mode 100644 src/Radarr.Api.V2/RootFolders/RootFolderResource.cs create mode 100644 src/Radarr.Api.V2/System/Backup/BackupModule.cs create mode 100644 src/Radarr.Api.V2/System/Backup/BackupResource.cs create mode 100644 src/Radarr.Api.V2/System/SystemModule.cs create mode 100644 src/Radarr.Api.V2/System/Tasks/TaskModule.cs create mode 100644 src/Radarr.Api.V2/System/Tasks/TaskResource.cs create mode 100644 src/Radarr.Api.V2/Tags/TagDetailsModule.cs create mode 100644 src/Radarr.Api.V2/Tags/TagDetailsResource.cs create mode 100644 src/Radarr.Api.V2/Tags/TagModule.cs create mode 100644 src/Radarr.Api.V2/Tags/TagResource.cs create mode 100644 src/Radarr.Api.V2/Update/UpdateModule.cs create mode 100644 src/Radarr.Api.V2/Update/UpdateResource.cs create mode 100644 src/Radarr.Api.V2/app.config create mode 100644 src/Radarr.Api.V2/packages.config rename src/{NzbDrone.Api => Radarr.Http}/Authentication/1tews5g3.gd1~ (100%) rename src/{NzbDrone.Api => Radarr.Http}/Authentication/AuthenticationModule.cs (89%) rename src/{NzbDrone.Api => Radarr.Http}/Authentication/AuthenticationService.cs (95%) rename src/{NzbDrone.Api => Radarr.Http}/Authentication/EnableAuthInNancy.cs (62%) rename src/{NzbDrone.Api => Radarr.Http}/Authentication/LoginResource.cs (81%) rename src/{NzbDrone.Api => Radarr.Http}/Authentication/NzbDroneUser.cs (85%) rename src/{NzbDrone.Api => Radarr.Http}/ClientSchema/Field.cs (63%) create mode 100644 src/Radarr.Http/ClientSchema/FieldMapping.cs create mode 100644 src/Radarr.Http/ClientSchema/SchemaBuilder.cs rename src/{NzbDrone.Api => Radarr.Http}/ClientSchema/SelectOption.cs (76%) rename src/{NzbDrone.Api => Radarr.Http}/ErrorManagement/ErrorHandler.cs (93%) rename src/{NzbDrone.Api => Radarr.Http}/ErrorManagement/ErrorModel.cs (83%) rename src/{NzbDrone.Api/ErrorManagement/NzbDroneErrorPipeline.cs => Radarr.Http/ErrorManagement/RadarrErrorPipeline.cs} (76%) rename src/{NzbDrone.Api/ErrorManagement => Radarr.Http/Exceptions}/ApiException.cs (90%) rename src/{NzbDrone.Api => Radarr.Http}/Exceptions/InvalidApiKeyException.cs (87%) rename src/{NzbDrone.Api => Radarr.Http}/Extensions/AccessControlHeaders.cs (92%) rename src/{NzbDrone.Api => Radarr.Http}/Extensions/NancyJsonSerializer.cs (93%) rename src/{NzbDrone.Api => Radarr.Http}/Extensions/Pipelines/CacheHeaderPipeline.cs (92%) rename src/{NzbDrone.Api => Radarr.Http}/Extensions/Pipelines/CorsPipeline.cs (93%) rename src/{NzbDrone.Api => Radarr.Http}/Extensions/Pipelines/GZipPipeline.cs (94%) rename src/{NzbDrone.Api => Radarr.Http}/Extensions/Pipelines/IRegisterNancyPipeline.cs (78%) rename src/{NzbDrone.Api => Radarr.Http}/Extensions/Pipelines/IfModifiedPipeline.cs (93%) rename src/{NzbDrone.Api/Extensions/Pipelines/NzbDroneVersionPipeline.cs => Radarr.Http/Extensions/Pipelines/RadarrVersionPipeline.cs} (81%) rename src/{NzbDrone.Api => Radarr.Http}/Extensions/Pipelines/RequestLoggingPipeline.cs (89%) rename src/{NzbDrone.Api => Radarr.Http}/Extensions/Pipelines/UrlBasePipeline.cs (94%) rename src/{NzbDrone.Api => Radarr.Http}/Extensions/ReqResExtensions.cs (98%) rename src/{NzbDrone.Api => Radarr.Http}/Extensions/RequestExtensions.cs (79%) rename src/{NzbDrone.Api => Radarr.Http}/Frontend/CacheableSpecification.cs (89%) create mode 100644 src/Radarr.Http/Frontend/InitializeJsModule.cs rename src/{NzbDrone.Api => Radarr.Http}/Frontend/Mappers/BackupFileMapper.cs (59%) create mode 100644 src/Radarr.Http/Frontend/Mappers/BrowserConfig.cs rename src/{NzbDrone.Api => Radarr.Http}/Frontend/Mappers/CacheBreakerProvider.cs (96%) rename src/{NzbDrone.Api => Radarr.Http}/Frontend/Mappers/FaviconMapper.cs (88%) create mode 100644 src/Radarr.Http/Frontend/Mappers/HtmlMapperBase.cs rename src/{NzbDrone.Api => Radarr.Http}/Frontend/Mappers/IMapHttpRequestsToDisk.cs (84%) create mode 100644 src/Radarr.Http/Frontend/Mappers/IndexHtmlMapper.cs rename src/{NzbDrone.Api => Radarr.Http}/Frontend/Mappers/LogFileMapper.cs (95%) create mode 100644 src/Radarr.Http/Frontend/Mappers/LoginHtmlMapper.cs create mode 100644 src/Radarr.Http/Frontend/Mappers/ManifestMapper.cs rename src/{NzbDrone.Api => Radarr.Http}/Frontend/Mappers/MediaCoverMapper.cs (97%) rename src/{NzbDrone.Api => Radarr.Http}/Frontend/Mappers/RobotsTxtMapper.cs (96%) rename src/{NzbDrone.Api => Radarr.Http}/Frontend/Mappers/StaticResourceMapper.cs (80%) rename src/{NzbDrone.Api => Radarr.Http}/Frontend/Mappers/StaticResourceMapperBase.cs (85%) rename src/{NzbDrone.Api => Radarr.Http}/Frontend/Mappers/UpdateLogFileMapper.cs (95%) rename src/{NzbDrone.Api => Radarr.Http}/Frontend/StaticResourceModule.cs (79%) create mode 100644 src/Radarr.Http/Mapping/MappingValidation.cs create mode 100644 src/Radarr.Http/Mapping/ResourceMappingException.cs rename src/{NzbDrone.Api => Radarr.Http}/PagingResource.cs (71%) create mode 100644 src/Radarr.Http/PagingResourceFilter.cs create mode 100644 src/Radarr.Http/Properties/AssemblyInfo.cs rename src/{NzbDrone.Api => Radarr.Http}/REST/BadRequestException.cs (76%) rename src/{NzbDrone.Api => Radarr.Http}/REST/MethodNotAllowedException.cs (78%) rename src/{NzbDrone.Api => Radarr.Http}/REST/NotFoundException.cs (76%) rename src/{NzbDrone.Api => Radarr.Http}/REST/ResourceValidator.cs (95%) rename src/{NzbDrone.Api => Radarr.Http}/REST/RestModule.cs (76%) rename src/{NzbDrone.Api => Radarr.Http}/REST/RestResource.cs (91%) create mode 100644 src/Radarr.Http/REST/UnsupportedMediaTypeException.cs create mode 100644 src/Radarr.Http/Radarr.Http.csproj rename src/{NzbDrone.Api/NancyBootstrapper.cs => Radarr.Http/RadarrBootstrapper.cs} (87%) rename src/{NzbDrone.Api/NzbDroneRestModule.cs => Radarr.Http/RadarrRestModule.cs} (54%) create mode 100644 src/Radarr.Http/RadarrRestModuleWithSignalR.cs rename src/{NzbDrone.Api => Radarr.Http}/ResourceChangeMessage.cs (93%) rename src/{NzbDrone.Api => Radarr.Http}/TinyIoCNancyBootstrapper.cs (99%) rename src/{NzbDrone.Api => Radarr.Http}/Validation/EmptyCollectionValidator.cs (94%) rename src/{NzbDrone.Api => Radarr.Http}/Validation/NetImportSyncIntervalValidator.cs (90%) rename src/{NzbDrone.Api => Radarr.Http}/Validation/RssSyncIntervalValidator.cs (80%) rename src/{NzbDrone.Api => Radarr.Http}/Validation/RuleBuilderExtensions.cs (83%) create mode 100644 src/Radarr.Http/app.config create mode 100644 src/Radarr.Http/packages.config create mode 100644 src/Radarr.sln diff --git a/src/NzbDrone.Api.Test/ClientSchemaTests/SchemaBuilderFixture.cs b/src/NzbDrone.Api.Test/ClientSchemaTests/SchemaBuilderFixture.cs index 385a9b989..24aee8f5e 100644 --- a/src/NzbDrone.Api.Test/ClientSchemaTests/SchemaBuilderFixture.cs +++ b/src/NzbDrone.Api.Test/ClientSchemaTests/SchemaBuilderFixture.cs @@ -1,6 +1,6 @@ -using FluentAssertions; +using FluentAssertions; using NUnit.Framework; -using NzbDrone.Api.ClientSchema; +using Radarr.Http.ClientSchema; using NzbDrone.Core.Annotations; using NzbDrone.Test.Common; @@ -28,8 +28,8 @@ namespace NzbDrone.Api.Test.ClientSchemaTests var schema = SchemaBuilder.ToSchema(model); - schema.Should().Contain(c => c.Order == 1 && c.Name == "LastName" && c.Label == "Last Name" && c.HelpText == "Your Last Name" && (string) c.Value == "Poop"); - schema.Should().Contain(c => c.Order == 0 && c.Name == "FirstName" && c.Label == "First Name" && c.HelpText == "Your First Name" && (string) c.Value == "Bob"); + schema.Should().Contain(c => c.Order == 1 && c.Name == "lastName" && c.Label == "Last Name" && c.HelpText == "Your Last Name" && (string) c.Value == "Poop"); + schema.Should().Contain(c => c.Order == 0 && c.Name == "firstName" && c.Label == "First Name" && c.HelpText == "Your First Name" && (string) c.Value == "Bob"); } } @@ -45,4 +45,4 @@ namespace NzbDrone.Api.Test.ClientSchemaTests public string Other { get; set; } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api.Test/NzbDrone.Api.Test.csproj b/src/NzbDrone.Api.Test/NzbDrone.Api.Test.csproj index 34c33d628..df6a64f8e 100644 --- a/src/NzbDrone.Api.Test/NzbDrone.Api.Test.csproj +++ b/src/NzbDrone.Api.Test/NzbDrone.Api.Test.csproj @@ -8,7 +8,7 @@ Library Properties NzbDrone.Api.Test - NzbDrone.Api.Test + Radarr.Api.Test v4.6.1 512 ..\ @@ -92,6 +92,10 @@ {CADDFCE0-7509-4430-8364-2074E1EEFCA2} NzbDrone.Test.Common + + {c5953dab-89db-46d9-a401-d620f54b776e} + Radarr.Http + diff --git a/src/NzbDrone.Api.Test/Properties/AssemblyInfo.cs b/src/NzbDrone.Api.Test/Properties/AssemblyInfo.cs index b45cbd098..db27f2a96 100644 --- a/src/NzbDrone.Api.Test/Properties/AssemblyInfo.cs +++ b/src/NzbDrone.Api.Test/Properties/AssemblyInfo.cs @@ -4,11 +4,11 @@ using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("NzbDrone.Api.Test")] +[assembly: AssemblyTitle("Radarr.Api.Test")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("NzbDrone.Api.Test")] +[assembly: AssemblyProduct("Radarr.Api.Test")] [assembly: AssemblyCopyright("Copyright © 2013")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/src/NzbDrone.Api/Blacklist/BlacklistModule.cs b/src/NzbDrone.Api/Blacklist/BlacklistModule.cs index 1687b31e3..36ab46b36 100644 --- a/src/NzbDrone.Api/Blacklist/BlacklistModule.cs +++ b/src/NzbDrone.Api/Blacklist/BlacklistModule.cs @@ -1,9 +1,10 @@ -using NzbDrone.Core.Blacklisting; +using NzbDrone.Core.Blacklisting; using NzbDrone.Core.Datastore; +using Radarr.Http; namespace NzbDrone.Api.Blacklist { - public class BlacklistModule : NzbDroneRestModule + public class BlacklistModule : RadarrRestModule { private readonly IBlacklistService _blacklistService; diff --git a/src/NzbDrone.Api/Blacklist/BlacklistResource.cs b/src/NzbDrone.Api/Blacklist/BlacklistResource.cs index f3259fd3c..acb6484e6 100644 --- a/src/NzbDrone.Api/Blacklist/BlacklistResource.cs +++ b/src/NzbDrone.Api/Blacklist/BlacklistResource.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using NzbDrone.Api.Movies; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Qualities; using NzbDrone.Core.Indexers; diff --git a/src/NzbDrone.Api/ClientSchema/FieldDefinitionAttribute.cs b/src/NzbDrone.Api/ClientSchema/FieldDefinitionAttribute.cs deleted file mode 100644 index 4e796bd8c..000000000 --- a/src/NzbDrone.Api/ClientSchema/FieldDefinitionAttribute.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace NzbDrone.Api.ClientSchema -{ - -} \ No newline at end of file diff --git a/src/NzbDrone.Api/ClientSchema/SchemaBuilder.cs b/src/NzbDrone.Api/ClientSchema/SchemaBuilder.cs deleted file mode 100644 index 496a1ed18..000000000 --- a/src/NzbDrone.Api/ClientSchema/SchemaBuilder.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Newtonsoft.Json.Linq; -using NzbDrone.Common.EnsureThat; -using NzbDrone.Common.Extensions; -using NzbDrone.Common.Reflection; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.Download.Clients.Nzbget; -using NzbDrone.Core.Qualities; -using NzbDrone.Core.Profiles; - -namespace NzbDrone.Api.ClientSchema -{ - public static class SchemaBuilder - { - public static List ToSchema(object model) - { - Ensure.That(model, () => model).IsNotNull(); - - var properties = model.GetType().GetSimpleProperties(); - - var result = new List(properties.Count); - - foreach (var propertyInfo in properties) - { - var fieldAttribute = propertyInfo.GetAttribute(false); - - if (fieldAttribute != null) - { - - var field = new Field - { - Name = propertyInfo.Name, - Label = fieldAttribute.Label, - HelpText = fieldAttribute.HelpText, - HelpLink = fieldAttribute.HelpLink, - Order = fieldAttribute.Order, - Advanced = fieldAttribute.Advanced, - Type = fieldAttribute.Type.ToString().ToLowerInvariant() - }; - - var value = propertyInfo.GetValue(model, null); - - if (propertyInfo.PropertyType.HasAttribute()) - { - int intVal = (int)value; - value = Enum.GetValues(propertyInfo.PropertyType) - .Cast() - .Where(f=> (f & intVal) == f) - .ToList(); - } - - if (value != null) - { - field.Value = value; - } - - if (fieldAttribute.Type == FieldType.Select || fieldAttribute.Type == FieldType.Tag) - { - field.SelectOptions = GetSelectOptions(fieldAttribute.SelectOptions); - } - - result.Add(field); - } - } - - return result.OrderBy(r => r.Order).ToList(); - } - - public static object ReadFromSchema(List fields, Type targetType) - { - Ensure.That(targetType, () => targetType).IsNotNull(); - - var properties = targetType.GetSimpleProperties(); - - var target = Activator.CreateInstance(targetType); - - foreach (var propertyInfo in properties) - { - var fieldAttribute = propertyInfo.GetAttribute(false); - - if (fieldAttribute != null) - { - var field = fields.Find(f => f.Name == propertyInfo.Name); - - if (propertyInfo.PropertyType == typeof(int)) - { - var value = field.Value.ToString().ParseInt32(); - propertyInfo.SetValue(target, value ?? 0, null); - } - - else if (propertyInfo.PropertyType == typeof(long)) - { - var value = field.Value.ToString().ParseInt64(); - propertyInfo.SetValue(target, value ?? 0, null); - } - - else if (propertyInfo.PropertyType == typeof(int?)) - { - var value = field.Value.ToString().ParseInt32(); - propertyInfo.SetValue(target, value, null); - } - - else if (propertyInfo.PropertyType == typeof(Nullable)) - { - var value = field.Value.ToString().ParseInt64(); - propertyInfo.SetValue(target, value, null); - } - - else if (propertyInfo.PropertyType == typeof(IEnumerable)) - { - IEnumerable value; - - if (field.Value?.GetType() == typeof(JArray)) - { - value = ((JArray)field.Value).Select(s => s.Value()); - } - - else - { - value = field.Value?.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => Convert.ToInt32(s)); - } - - propertyInfo.SetValue(target, value, null); - } - - else if (propertyInfo.PropertyType == typeof(IEnumerable)) - { - IEnumerable value; - - if (field.Value.GetType() == typeof(JArray)) - { - value = ((JArray)field.Value).Select(s => s.Value()); - } - - else - { - value = field.Value.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - } - - propertyInfo.SetValue(target, value, null); - } - - else if (propertyInfo.PropertyType.HasAttribute()) - { - int value = field.Value.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => Convert.ToInt32(s)).Sum(); - propertyInfo.SetValue(target, value, null); - } - - else - { - propertyInfo.SetValue(target, field.Value, null); - } - } - } - - return target; - - } - - public static T ReadFromSchema(List fields) - { - return (T)ReadFromSchema(fields, typeof(T)); - } - - private static List GetSelectOptions(Type selectOptions) - { - if (selectOptions == null || selectOptions == typeof(Profile)) - { - return new List(); - } - - if (selectOptions == typeof(Quality)) - { - var qOptions = from Quality q in selectOptions.GetProperties(BindingFlags.Static | BindingFlags.Public) - select new SelectOption {Name = q.Name, Value = q.Id}; - return qOptions.OrderBy(o => o.Value).ToList(); - } - - var options = from Enum e in Enum.GetValues(selectOptions) - select new SelectOption { Value = Convert.ToInt32(e), Name = e.ToString() }; - - if (selectOptions == typeof(NzbgetPriority)) - { - return options.OrderBy(o => o.Value).ToList(); - } - - return options.OrderBy(o => o.Name).ToList(); - } - } -} diff --git a/src/NzbDrone.Api/ClientSchema/SchemaDeserializer.cs b/src/NzbDrone.Api/ClientSchema/SchemaDeserializer.cs deleted file mode 100644 index 6af07257f..000000000 --- a/src/NzbDrone.Api/ClientSchema/SchemaDeserializer.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace NzbDrone.Api.ClientSchema -{ - public static class SchemaDeserializer - { - - } -} \ No newline at end of file diff --git a/src/NzbDrone.Api/Commands/CommandModule.cs b/src/NzbDrone.Api/Commands/CommandModule.cs index 1395d68ec..f828845ed 100644 --- a/src/NzbDrone.Api/Commands/CommandModule.cs +++ b/src/NzbDrone.Api/Commands/CommandModule.cs @@ -1,20 +1,22 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using NLog; -using NzbDrone.Api.Extensions; -using NzbDrone.Api.Validation; +using Radarr.Http.Extensions; +using Radarr.Http.Validation; using NzbDrone.Common; using NzbDrone.Core.Datastore.Events; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.ProgressMessaging; using NzbDrone.SignalR; +using Radarr.Http; +using Radarr.Http.Mapping; namespace NzbDrone.Api.Commands { - public class CommandModule : NzbDroneRestModuleWithSignalR, IHandle + public class CommandModule : RadarrRestModuleWithSignalR, IHandle { private readonly IManageCommandQueue _commandQueueManager; private readonly IServiceFactory _serviceFactory; @@ -73,4 +75,4 @@ namespace NzbDrone.Api.Commands } } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Commands/CommandResource.cs b/src/NzbDrone.Api/Commands/CommandResource.cs index cf09f12ac..29a72ebe4 100644 --- a/src/NzbDrone.Api/Commands/CommandResource.cs +++ b/src/NzbDrone.Api/Commands/CommandResource.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Messaging.Commands; namespace NzbDrone.Api.Commands diff --git a/src/NzbDrone.Api/Config/DownloadClientConfigModule.cs b/src/NzbDrone.Api/Config/DownloadClientConfigModule.cs index e4fdef50f..3e19e7564 100644 --- a/src/NzbDrone.Api/Config/DownloadClientConfigModule.cs +++ b/src/NzbDrone.Api/Config/DownloadClientConfigModule.cs @@ -1,4 +1,4 @@ -using FluentValidation; +using FluentValidation; using NzbDrone.Core.Configuration; using NzbDrone.Core.Validation.Paths; @@ -6,19 +6,10 @@ namespace NzbDrone.Api.Config { public class DownloadClientConfigModule : NzbDroneConfigModule { - public DownloadClientConfigModule(IConfigService configService, - RootFolderValidator rootFolderValidator, - PathExistsValidator pathExistsValidator, - MappedNetworkDriveValidator mappedNetworkDriveValidator) + public DownloadClientConfigModule(IConfigService configService) : base(configService) { - SharedValidator.RuleFor(c => c.DownloadedMoviesFolder) - .Cascade(CascadeMode.StopOnFirstFailure) - .IsValidPath() - .SetValidator(rootFolderValidator) - .SetValidator(mappedNetworkDriveValidator) - .SetValidator(pathExistsValidator) - .When(c => !string.IsNullOrWhiteSpace(c.DownloadedMoviesFolder)); + } protected override DownloadClientConfigResource ToResource(IConfigService model) @@ -26,4 +17,4 @@ namespace NzbDrone.Api.Config return DownloadClientConfigResourceMapper.ToResource(model); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs b/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs index 4d3a08add..cd7430817 100644 --- a/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs +++ b/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs @@ -1,13 +1,11 @@ -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Configuration; namespace NzbDrone.Api.Config { public class DownloadClientConfigResource : RestResource { - public string DownloadedMoviesFolder { get; set; } public string DownloadClientWorkingFolders { get; set; } - public int DownloadedMoviesScanInterval { get; set; } public bool EnableCompletedDownloadHandling { get; set; } public bool RemoveCompletedDownloads { get; set; } @@ -23,9 +21,7 @@ namespace NzbDrone.Api.Config { return new DownloadClientConfigResource { - DownloadedMoviesFolder = model.DownloadedMoviesFolder, DownloadClientWorkingFolders = model.DownloadClientWorkingFolders, - DownloadedMoviesScanInterval = model.DownloadedMoviesScanInterval, EnableCompletedDownloadHandling = model.EnableCompletedDownloadHandling, RemoveCompletedDownloads = model.RemoveCompletedDownloads, diff --git a/src/NzbDrone.Api/Config/HostConfigModule.cs b/src/NzbDrone.Api/Config/HostConfigModule.cs index 367bf770d..23a59b676 100644 --- a/src/NzbDrone.Api/Config/HostConfigModule.cs +++ b/src/NzbDrone.Api/Config/HostConfigModule.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.IO; +using System.Linq; using System.Reflection; using FluentValidation; using NzbDrone.Common.EnvironmentInfo; @@ -8,10 +9,11 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.Update; using NzbDrone.Core.Validation; using NzbDrone.Core.Validation.Paths; +using Radarr.Http; namespace NzbDrone.Api.Config { - public class HostConfigModule : NzbDroneRestModule + public class HostConfigModule : RadarrRestModule { private readonly IConfigFileProvider _configFileProvider; private readonly IConfigService _configService; @@ -45,6 +47,10 @@ namespace NzbDrone.Api.Config SharedValidator.RuleFor(c => c.Branch).NotEmpty().WithMessage("Branch name is required, 'master' is the default"); SharedValidator.RuleFor(c => c.UpdateScriptPath).IsValidPath().When(c => c.UpdateMechanism == UpdateMechanism.Script); + + SharedValidator.RuleFor(c => c.BackupFolder).IsValidPath().When(c => Path.IsPathRooted(c.BackupFolder)); + SharedValidator.RuleFor(c => c.BackupInterval).InclusiveBetween(1, 7); + SharedValidator.RuleFor(c => c.BackupRetention).InclusiveBetween(1, 90); } private HostConfigResource GetHostConfig() diff --git a/src/NzbDrone.Api/Config/HostConfigResource.cs b/src/NzbDrone.Api/Config/HostConfigResource.cs index 930e0301c..a7e042db1 100644 --- a/src/NzbDrone.Api/Config/HostConfigResource.cs +++ b/src/NzbDrone.Api/Config/HostConfigResource.cs @@ -1,4 +1,4 @@ -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Authentication; using NzbDrone.Core.Configuration; using NzbDrone.Core.Update; @@ -33,6 +33,9 @@ namespace NzbDrone.Api.Config public string ProxyPassword { get; set; } public string ProxyBypassFilter { get; set; } public bool ProxyBypassLocalAddresses { get; set; } + public string BackupFolder { get; set; } + public int BackupInterval { get; set; } + public int BackupRetention { get; set; } } public static class HostConfigResourceMapper @@ -66,7 +69,10 @@ namespace NzbDrone.Api.Config ProxyUsername = configService.ProxyUsername, ProxyPassword = configService.ProxyPassword, ProxyBypassFilter = configService.ProxyBypassFilter, - ProxyBypassLocalAddresses = configService.ProxyBypassLocalAddresses + ProxyBypassLocalAddresses = configService.ProxyBypassLocalAddresses, + BackupFolder = configService.BackupFolder, + BackupInterval = configService.BackupInterval, + BackupRetention = configService.BackupRetention }; } } diff --git a/src/NzbDrone.Api/Config/IndexerConfigModule.cs b/src/NzbDrone.Api/Config/IndexerConfigModule.cs index db5299944..7c80ef1a9 100644 --- a/src/NzbDrone.Api/Config/IndexerConfigModule.cs +++ b/src/NzbDrone.Api/Config/IndexerConfigModule.cs @@ -1,5 +1,5 @@ using FluentValidation; -using NzbDrone.Api.Validation; +using Radarr.Http.Validation; using NzbDrone.Core.Configuration; namespace NzbDrone.Api.Config diff --git a/src/NzbDrone.Api/Config/IndexerConfigResource.cs b/src/NzbDrone.Api/Config/IndexerConfigResource.cs index bdcfbfd9c..854ea6b51 100644 --- a/src/NzbDrone.Api/Config/IndexerConfigResource.cs +++ b/src/NzbDrone.Api/Config/IndexerConfigResource.cs @@ -1,4 +1,4 @@ -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Configuration; using NzbDrone.Core.Parser; diff --git a/src/NzbDrone.Api/Config/MediaManagementConfigResource.cs b/src/NzbDrone.Api/Config/MediaManagementConfigResource.cs index e5147e601..53e03e87e 100644 --- a/src/NzbDrone.Api/Config/MediaManagementConfigResource.cs +++ b/src/NzbDrone.Api/Config/MediaManagementConfigResource.cs @@ -1,4 +1,4 @@ -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Configuration; using NzbDrone.Core.MediaFiles; @@ -33,10 +33,10 @@ namespace NzbDrone.Api.Config { return new MediaManagementConfigResource { - AutoUnmonitorPreviouslyDownloadedEpisodes = model.AutoUnmonitorPreviouslyDownloadedEpisodes, + AutoUnmonitorPreviouslyDownloadedEpisodes = model.AutoUnmonitorPreviouslyDownloadedMovies, RecycleBin = model.RecycleBin, AutoDownloadPropers = model.AutoDownloadPropers, - CreateEmptySeriesFolders = model.CreateEmptySeriesFolders, + CreateEmptySeriesFolders = model.CreateEmptyMovieFolders, FileDate = model.FileDate, AutoRenameFolders = model.AutoRenameFolders, PathsDefaultStatic = model.PathsDefaultStatic, diff --git a/src/NzbDrone.Api/Config/NamingConfigModule.cs b/src/NzbDrone.Api/Config/NamingConfigModule.cs index 42efaa49a..77422568c 100644 --- a/src/NzbDrone.Api/Config/NamingConfigModule.cs +++ b/src/NzbDrone.Api/Config/NamingConfigModule.cs @@ -6,11 +6,13 @@ using Nancy.Responses; using NzbDrone.Common.Extensions; using NzbDrone.Core.Organizer; using Nancy.ModelBinding; -using NzbDrone.Api.Extensions; +using Radarr.Http.Extensions; +using Radarr.Http; +using Radarr.Http.Mapping; namespace NzbDrone.Api.Config { - public class NamingConfigModule : NzbDroneRestModule + public class NamingConfigModule : RadarrRestModule { private readonly INamingConfigService _namingConfigService; private readonly IFilenameSampleService _filenameSampleService; diff --git a/src/NzbDrone.Api/Config/NamingConfigResource.cs b/src/NzbDrone.Api/Config/NamingConfigResource.cs index 9e657e36e..131f6459c 100644 --- a/src/NzbDrone.Api/Config/NamingConfigResource.cs +++ b/src/NzbDrone.Api/Config/NamingConfigResource.cs @@ -1,4 +1,4 @@ -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Organizer; namespace NzbDrone.Api.Config diff --git a/src/NzbDrone.Api/Config/NetImportConfigModule.cs b/src/NzbDrone.Api/Config/NetImportConfigModule.cs index f805e8c2d..d93f3b18b 100644 --- a/src/NzbDrone.Api/Config/NetImportConfigModule.cs +++ b/src/NzbDrone.Api/Config/NetImportConfigModule.cs @@ -1,5 +1,5 @@ -using FluentValidation; -using NzbDrone.Api.Validation; +using FluentValidation; +using Radarr.Http.Validation; using NzbDrone.Core.Configuration; namespace NzbDrone.Api.Config @@ -19,4 +19,4 @@ namespace NzbDrone.Api.Config return NetImportConfigResourceMapper.ToResource(model); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Config/NetImportConfigResource.cs b/src/NzbDrone.Api/Config/NetImportConfigResource.cs index 942a2177d..c70b25ed2 100644 --- a/src/NzbDrone.Api/Config/NetImportConfigResource.cs +++ b/src/NzbDrone.Api/Config/NetImportConfigResource.cs @@ -1,4 +1,4 @@ -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Configuration; namespace NzbDrone.Api.Config diff --git a/src/NzbDrone.Api/Config/NzbDroneConfigModule.cs b/src/NzbDrone.Api/Config/NzbDroneConfigModule.cs index e5d324950..acc29f8bf 100644 --- a/src/NzbDrone.Api/Config/NzbDroneConfigModule.cs +++ b/src/NzbDrone.Api/Config/NzbDroneConfigModule.cs @@ -1,11 +1,12 @@ -using System.Linq; +using System.Linq; using System.Reflection; -using NzbDrone.Api.REST; +using Radarr.Http; +using Radarr.Http.REST; using NzbDrone.Core.Configuration; namespace NzbDrone.Api.Config { - public abstract class NzbDroneConfigModule : NzbDroneRestModule where TResource : RestResource, new() + public abstract class NzbDroneConfigModule : RadarrRestModule where TResource : RestResource, new() { private readonly IConfigService _configService; diff --git a/src/NzbDrone.Api/Config/UiConfigResource.cs b/src/NzbDrone.Api/Config/UiConfigResource.cs index 7c7d27b67..988b976b6 100644 --- a/src/NzbDrone.Api/Config/UiConfigResource.cs +++ b/src/NzbDrone.Api/Config/UiConfigResource.cs @@ -1,4 +1,4 @@ -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Configuration; namespace NzbDrone.Api.Config diff --git a/src/NzbDrone.Api/DiskSpace/DiskSpaceModule.cs b/src/NzbDrone.Api/DiskSpace/DiskSpaceModule.cs index f6d8354b4..0a43fad9b 100644 --- a/src/NzbDrone.Api/DiskSpace/DiskSpaceModule.cs +++ b/src/NzbDrone.Api/DiskSpace/DiskSpaceModule.cs @@ -1,9 +1,10 @@ -using System.Collections.Generic; +using System.Collections.Generic; using NzbDrone.Core.DiskSpace; +using Radarr.Http; namespace NzbDrone.Api.DiskSpace { - public class DiskSpaceModule :NzbDroneRestModule + public class DiskSpaceModule :RadarrRestModule { private readonly IDiskSpaceService _diskSpaceService; diff --git a/src/NzbDrone.Api/DiskSpace/DiskSpaceResource.cs b/src/NzbDrone.Api/DiskSpace/DiskSpaceResource.cs index fc36f9d5c..f95c2d2a4 100644 --- a/src/NzbDrone.Api/DiskSpace/DiskSpaceResource.cs +++ b/src/NzbDrone.Api/DiskSpace/DiskSpaceResource.cs @@ -1,4 +1,4 @@ -using NzbDrone.Api.REST; +using Radarr.Http.REST; namespace NzbDrone.Api.DiskSpace { diff --git a/src/NzbDrone.Api/ExtraFiles/ExtraFileModule.cs b/src/NzbDrone.Api/ExtraFiles/ExtraFileModule.cs index ed48df23b..040aae79a 100644 --- a/src/NzbDrone.Api/ExtraFiles/ExtraFileModule.cs +++ b/src/NzbDrone.Api/ExtraFiles/ExtraFileModule.cs @@ -1,13 +1,14 @@ using System.Collections.Generic; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Extras.Files; using NzbDrone.Core.Extras.Metadata.Files; using NzbDrone.Core.Extras.Others; using NzbDrone.Core.Extras.Subtitles; +using Radarr.Http; namespace NzbDrone.Api.ExtraFiles { - public class ExtraFileModule : NzbDroneRestModule + public class ExtraFileModule : RadarrRestModule { private readonly IExtraFileService _subtitleFileService; private readonly IExtraFileService _metadataFileService; diff --git a/src/NzbDrone.Api/ExtraFiles/ExtraFileResource.cs b/src/NzbDrone.Api/ExtraFiles/ExtraFileResource.cs index e4f19475b..667f7ca47 100644 --- a/src/NzbDrone.Api/ExtraFiles/ExtraFileResource.cs +++ b/src/NzbDrone.Api/ExtraFiles/ExtraFileResource.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Extras.Files; using NzbDrone.Core.Extras.Metadata.Files; using NzbDrone.Core.Extras.Others; diff --git a/src/NzbDrone.Api/FileSystem/FileSystemModule.cs b/src/NzbDrone.Api/FileSystem/FileSystemModule.cs index 67c2be7bd..47c2773e2 100644 --- a/src/NzbDrone.Api/FileSystem/FileSystemModule.cs +++ b/src/NzbDrone.Api/FileSystem/FileSystemModule.cs @@ -1,8 +1,8 @@ -using System; +using System; using System.IO; using System.Linq; using Nancy; -using NzbDrone.Api.Extensions; +using Radarr.Http.Extensions; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; using NzbDrone.Core.MediaFiles; @@ -31,15 +31,10 @@ namespace NzbDrone.Api.FileSystem private Response GetContents() { var pathQuery = Request.Query.path; - var includeFilesQuery = Request.Query.includeFiles; - bool includeFiles = false; + var includeFiles = Request.GetBooleanQueryParameter("includeFiles"); + var allowFoldersWithoutTrailingSlashes = Request.GetBooleanQueryParameter("allowFoldersWithoutTrailingSlashes"); - if (includeFilesQuery.HasValue) - { - includeFiles = Convert.ToBoolean(includeFilesQuery.Value); - } - - return _fileSystemLookupService.LookupContents((string)pathQuery.Value, includeFiles).AsResponse(); + return _fileSystemLookupService.LookupContents((string)pathQuery.Value, includeFiles, allowFoldersWithoutTrailingSlashes).AsResponse(); } private Response GetEntityType() @@ -73,4 +68,4 @@ namespace NzbDrone.Api.FileSystem }).AsResponse(); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs b/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs deleted file mode 100644 index 46b5d9c37..000000000 --- a/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System; -using System.IO; -using System.Text.RegularExpressions; -using Nancy; -using NLog; -using NzbDrone.Common.Disk; -using NzbDrone.Common.EnvironmentInfo; -using NzbDrone.Core.Analytics; -using NzbDrone.Core.Configuration; - -namespace NzbDrone.Api.Frontend.Mappers -{ - public class IndexHtmlMapper : StaticResourceMapperBase - { - private readonly IDiskProvider _diskProvider; - private readonly IConfigFileProvider _configFileProvider; - private readonly IAnalyticsService _analyticsService; - private readonly Func _cacheBreakProviderFactory; - private readonly string _indexPath; - private static readonly Regex ReplaceRegex = new Regex(@"(?:(?href|src|content)=\"")(?.*?(?css|js|png|ico|ics|svg|json|xml))(?:\"")(?:\s(?data-no-hash))?", RegexOptions.Compiled | RegexOptions.IgnoreCase); - - private static string API_KEY; - private static string URL_BASE; - private string _generatedContent - ; - - public IndexHtmlMapper(IAppFolderInfo appFolderInfo, - IDiskProvider diskProvider, - IConfigFileProvider configFileProvider, - IAnalyticsService analyticsService, - Func cacheBreakProviderFactory, - Logger logger) - : base(diskProvider, logger) - { - _diskProvider = diskProvider; - _configFileProvider = configFileProvider; - _analyticsService = analyticsService; - _cacheBreakProviderFactory = cacheBreakProviderFactory; - _indexPath = Path.Combine(appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, "index.html"); - - API_KEY = configFileProvider.ApiKey; - URL_BASE = configFileProvider.UrlBase; - } - - public override string Map(string resourceUrl) - { - return _indexPath; - } - - public override bool CanHandle(string resourceUrl) - { - resourceUrl = resourceUrl.ToLowerInvariant(); - - return !resourceUrl.StartsWith("/content") && - !resourceUrl.StartsWith("/mediacover") && - !resourceUrl.Contains(".") && - !resourceUrl.StartsWith("/login"); - } - - public override Response GetResponse(string resourceUrl) - { - var response = base.GetResponse(resourceUrl); - response.Headers["X-UA-Compatible"] = "IE=edge"; - - return response; - } - - protected override Stream GetContentStream(string filePath) - { - var text = GetIndexText(); - - var stream = new MemoryStream(); - var writer = new StreamWriter(stream); - writer.Write(text); - writer.Flush(); - stream.Position = 0; - return stream; - } - - private string GetIndexText() - { - if (RuntimeInfo.IsProduction && _generatedContent != null) - { - return _generatedContent; - } - - var text = _diskProvider.ReadAllText(_indexPath); - - var cacheBreakProvider = _cacheBreakProviderFactory(); - - text = ReplaceRegex.Replace(text, match => - { - string url; - - if (match.Groups["nohash"].Success) - { - url = match.Groups["path"].Value; - } - - else - { - url = cacheBreakProvider.AddCacheBreakerToPath(match.Groups["path"].Value); - } - - return string.Format("{0}=\"{1}{2}\"", match.Groups["attribute"].Value, URL_BASE, url); - }); - - text = text.Replace("API_ROOT", URL_BASE + "/api"); - text = text.Replace("API_KEY", API_KEY); - text = text.Replace("APP_VERSION", BuildInfo.Version.ToString()); - text = text.Replace("APP_BRANCH", _configFileProvider.Branch.ToLower()); - text = text.Replace("APP_ANALYTICS", _analyticsService.IsEnabled.ToString().ToLowerInvariant()); - text = text.Replace("URL_BASE", URL_BASE); - text = text.Replace("PRODUCTION", RuntimeInfo.IsProduction.ToString().ToLowerInvariant()); - - _generatedContent = text; - - return _generatedContent; - } - } -} diff --git a/src/NzbDrone.Api/Frontend/Mappers/LoginHtmlMapper.cs b/src/NzbDrone.Api/Frontend/Mappers/LoginHtmlMapper.cs deleted file mode 100644 index 974e117f9..000000000 --- a/src/NzbDrone.Api/Frontend/Mappers/LoginHtmlMapper.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.IO; -using System.Text.RegularExpressions; -using Nancy; -using NLog; -using NzbDrone.Common.Disk; -using NzbDrone.Common.EnvironmentInfo; -using NzbDrone.Core.Configuration; - -namespace NzbDrone.Api.Frontend.Mappers -{ - public class LoginHtmlMapper : StaticResourceMapperBase - { - private readonly IDiskProvider _diskProvider; - private readonly IConfigFileProvider _configFileProvider; - private readonly Func _cacheBreakProviderFactory; - private readonly string _indexPath; - private static readonly Regex ReplaceRegex = new Regex("(?<=(?:href|src|data-main)=\").*?(?=\")", RegexOptions.Compiled | RegexOptions.IgnoreCase); - - private static string URL_BASE; - private string _generatedContent; - - public LoginHtmlMapper(IAppFolderInfo appFolderInfo, - IDiskProvider diskProvider, - IConfigFileProvider configFileProvider, - Func cacheBreakProviderFactory, - Logger logger) - : base(diskProvider, logger) - { - _diskProvider = diskProvider; - _configFileProvider = configFileProvider; - _cacheBreakProviderFactory = cacheBreakProviderFactory; - _indexPath = Path.Combine(appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, "login.html"); - - URL_BASE = configFileProvider.UrlBase; - } - - public override string Map(string resourceUrl) - { - return _indexPath; - } - - public override bool CanHandle(string resourceUrl) - { - return resourceUrl.StartsWith("/login"); - } - - public override Response GetResponse(string resourceUrl) - { - var response = base.GetResponse(resourceUrl); - response.Headers["X-UA-Compatible"] = "IE=edge"; - - return response; - } - - protected override Stream GetContentStream(string filePath) - { - var text = GetLoginText(); - - var stream = new MemoryStream(); - var writer = new StreamWriter(stream); - writer.Write(text); - writer.Flush(); - stream.Position = 0; - return stream; - } - - private string GetLoginText() - { - if (RuntimeInfo.IsProduction && _generatedContent != null) - { - return _generatedContent; - } - - var text = _diskProvider.ReadAllText(_indexPath); - - var cacheBreakProvider = _cacheBreakProviderFactory(); - - text = ReplaceRegex.Replace(text, match => - { - var url = cacheBreakProvider.AddCacheBreakerToPath(match.Value); - return URL_BASE + url; - }); - - _generatedContent = text; - - return _generatedContent; - } - } -} diff --git a/src/NzbDrone.Api/Health/HealthModule.cs b/src/NzbDrone.Api/Health/HealthModule.cs index 2699fa7d6..b7e96fac6 100644 --- a/src/NzbDrone.Api/Health/HealthModule.cs +++ b/src/NzbDrone.Api/Health/HealthModule.cs @@ -1,12 +1,13 @@ -using System.Collections.Generic; +using System.Collections.Generic; using NzbDrone.Core.Datastore.Events; using NzbDrone.Core.HealthCheck; using NzbDrone.Core.Messaging.Events; using NzbDrone.SignalR; +using Radarr.Http; namespace NzbDrone.Api.Health { - public class HealthModule : NzbDroneRestModuleWithSignalR, + public class HealthModule : RadarrRestModuleWithSignalR, IHandle { private readonly IHealthCheckService _healthCheckService; @@ -28,4 +29,4 @@ namespace NzbDrone.Api.Health BroadcastResourceChange(ModelAction.Sync); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Health/HealthResource.cs b/src/NzbDrone.Api/Health/HealthResource.cs index e860cb778..8be8a5899 100644 --- a/src/NzbDrone.Api/Health/HealthResource.cs +++ b/src/NzbDrone.Api/Health/HealthResource.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Common.Http; using NzbDrone.Core.HealthCheck; diff --git a/src/NzbDrone.Api/History/HistoryModule.cs b/src/NzbDrone.Api/History/HistoryModule.cs index 2e2c8d004..a5797c14a 100644 --- a/src/NzbDrone.Api/History/HistoryModule.cs +++ b/src/NzbDrone.Api/History/HistoryModule.cs @@ -1,15 +1,18 @@ using System; +using System.Linq; using Nancy; -using NzbDrone.Api.Extensions; +using Radarr.Http.Extensions; using NzbDrone.Api.Movies; using NzbDrone.Core.Datastore; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Download; using NzbDrone.Core.History; +using Radarr.Http; +using Radarr.Http.REST; namespace NzbDrone.Api.History { - public class HistoryModule : NzbDroneRestModule + public class HistoryModule : RadarrRestModule { private readonly IHistoryService _historyService; private readonly IQualityUpgradableSpecification _qualityUpgradableSpecification; @@ -43,19 +46,19 @@ namespace NzbDrone.Api.History private PagingResource GetHistory(PagingResource pagingResource) { var movieId = Request.Query.MovieId; - var pagingSpec = pagingResource.MapToPagingSpec("date", SortDirection.Descending); + var filter = pagingResource.Filters.FirstOrDefault(); - if (pagingResource.FilterKey == "eventType") + if (filter != null && filter.Key == "eventType") { - var filterValue = (HistoryEventType)Convert.ToInt32(pagingResource.FilterValue); - pagingSpec.FilterExpression = v => v.EventType == filterValue; + var filterValue = (HistoryEventType)Convert.ToInt32(filter.Value); + pagingSpec.FilterExpressions.Add(v => v.EventType == filterValue); } if (movieId.HasValue) { int i = (int)movieId; - pagingSpec.FilterExpression = h => h.MovieId == i; + pagingSpec.FilterExpressions.Add(h => h.MovieId == i); } return ApplyToPage(_historyService.Paged, pagingSpec, MapToResource); diff --git a/src/NzbDrone.Api/History/HistoryResource.cs b/src/NzbDrone.Api/History/HistoryResource.cs index c4415d079..c976a9d2d 100644 --- a/src/NzbDrone.Api/History/HistoryResource.cs +++ b/src/NzbDrone.Api/History/HistoryResource.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Api.Movies; using NzbDrone.Core.History; using NzbDrone.Core.Qualities; diff --git a/src/NzbDrone.Api/Indexers/ReleaseModule.cs b/src/NzbDrone.Api/Indexers/ReleaseModule.cs index 510ceac86..ba449cc57 100644 --- a/src/NzbDrone.Api/Indexers/ReleaseModule.cs +++ b/src/NzbDrone.Api/Indexers/ReleaseModule.cs @@ -10,7 +10,7 @@ using NzbDrone.Core.IndexerSearch; using NzbDrone.Core.Indexers; using NzbDrone.Core.Parser.Model; using Nancy.ModelBinding; -using NzbDrone.Api.Extensions; +using Radarr.Http.Extensions; using NzbDrone.Common.Cache; using HttpStatusCode = System.Net.HttpStatusCode; diff --git a/src/NzbDrone.Api/Indexers/ReleaseModuleBase.cs b/src/NzbDrone.Api/Indexers/ReleaseModuleBase.cs index c615f947d..3dca0acce 100644 --- a/src/NzbDrone.Api/Indexers/ReleaseModuleBase.cs +++ b/src/NzbDrone.Api/Indexers/ReleaseModuleBase.cs @@ -1,9 +1,10 @@ -using System.Collections.Generic; +using System.Collections.Generic; using NzbDrone.Core.DecisionEngine; +using Radarr.Http; namespace NzbDrone.Api.Indexers { - public abstract class ReleaseModuleBase : NzbDroneRestModule + public abstract class ReleaseModuleBase : RadarrRestModule { protected virtual List MapDecisions(IEnumerable decisions) { diff --git a/src/NzbDrone.Api/Indexers/ReleasePushModule.cs b/src/NzbDrone.Api/Indexers/ReleasePushModule.cs index c25e45726..63b7278b6 100644 --- a/src/NzbDrone.Api/Indexers/ReleasePushModule.cs +++ b/src/NzbDrone.Api/Indexers/ReleasePushModule.cs @@ -1,4 +1,4 @@ -using Nancy; +using Nancy; using Nancy.ModelBinding; using FluentValidation; using NzbDrone.Core.DecisionEngine; @@ -6,7 +6,8 @@ using NzbDrone.Core.Download; using System.Collections.Generic; using System.Linq; using NzbDrone.Core.Parser.Model; -using NzbDrone.Api.Extensions; +using Radarr.Http.Extensions; +using Radarr.Http.Mapping; using NLog; namespace NzbDrone.Api.Indexers diff --git a/src/NzbDrone.Api/Indexers/ReleaseResource.cs b/src/NzbDrone.Api/Indexers/ReleaseResource.cs index 4b6410956..eaa2779bc 100644 --- a/src/NzbDrone.Api/Indexers/ReleaseResource.cs +++ b/src/NzbDrone.Api/Indexers/ReleaseResource.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using Newtonsoft.Json; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Parser; using NzbDrone.Core.Qualities; using NzbDrone.Core.Indexers; diff --git a/src/NzbDrone.Api/Logs/LogFileModuleBase.cs b/src/NzbDrone.Api/Logs/LogFileModuleBase.cs index d8a12d1bf..e719bafdd 100644 --- a/src/NzbDrone.Api/Logs/LogFileModuleBase.cs +++ b/src/NzbDrone.Api/Logs/LogFileModuleBase.cs @@ -1,14 +1,15 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; using NzbDrone.Common.Disk; using Nancy; using Nancy.Responses; using NzbDrone.Core.Configuration; +using Radarr.Http; namespace NzbDrone.Api.Logs { - public abstract class LogFileModuleBase : NzbDroneRestModule + public abstract class LogFileModuleBase : RadarrRestModule { protected const string LOGFILE_ROUTE = @"/(?[-.a-zA-Z0-9]+?\.txt)"; @@ -68,4 +69,4 @@ namespace NzbDrone.Api.Logs protected abstract string DownloadUrlRoot { get; } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Logs/LogFileResource.cs b/src/NzbDrone.Api/Logs/LogFileResource.cs index 9f67c8af7..8dec96418 100644 --- a/src/NzbDrone.Api/Logs/LogFileResource.cs +++ b/src/NzbDrone.Api/Logs/LogFileResource.cs @@ -1,5 +1,5 @@ using System; -using NzbDrone.Api.REST; +using Radarr.Http.REST; namespace NzbDrone.Api.Logs { diff --git a/src/NzbDrone.Api/Logs/LogModule.cs b/src/NzbDrone.Api/Logs/LogModule.cs index 88ead3ec0..d671198db 100644 --- a/src/NzbDrone.Api/Logs/LogModule.cs +++ b/src/NzbDrone.Api/Logs/LogModule.cs @@ -1,8 +1,10 @@ -using NzbDrone.Core.Instrumentation; +using System.Linq; +using NzbDrone.Core.Instrumentation; +using Radarr.Http; namespace NzbDrone.Api.Logs { - public class LogModule : NzbDroneRestModule + public class LogModule : RadarrRestModule { private readonly ILogService _logService; @@ -21,27 +23,29 @@ namespace NzbDrone.Api.Logs pageSpec.SortKey = "id"; } - if (pagingResource.FilterKey == "level") + var filter = pagingResource.Filters.FirstOrDefault(); + + if (filter != null && filter.Key == "level") { - switch (pagingResource.FilterValue) + switch (filter.Value) { case "Fatal": - pageSpec.FilterExpression = h => h.Level == "Fatal"; + pageSpec.FilterExpressions.Add(h => h.Level == "Fatal"); break; case "Error": - pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error"; + pageSpec.FilterExpressions.Add(h => h.Level == "Fatal" || h.Level == "Error"); break; case "Warn": - pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn"; + pageSpec.FilterExpressions.Add(h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn"); break; case "Info": - pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info"; + pageSpec.FilterExpressions.Add(h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info"); break; case "Debug": - pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info" || h.Level == "Debug"; + pageSpec.FilterExpressions.Add(h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info" || h.Level == "Debug"); break; case "Trace": - pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info" || h.Level == "Debug" || h.Level == "Trace"; + pageSpec.FilterExpressions.Add(h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info" || h.Level == "Debug" || h.Level == "Trace"); break; } } @@ -49,4 +53,4 @@ namespace NzbDrone.Api.Logs return ApplyToPage(_logService.Paged, pageSpec, LogResourceMapper.ToResource); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Logs/LogResource.cs b/src/NzbDrone.Api/Logs/LogResource.cs index 504a45839..53d9a947a 100644 --- a/src/NzbDrone.Api/Logs/LogResource.cs +++ b/src/NzbDrone.Api/Logs/LogResource.cs @@ -1,5 +1,5 @@ using System; -using NzbDrone.Api.REST; +using Radarr.Http.REST; namespace NzbDrone.Api.Logs { diff --git a/src/NzbDrone.Api/ManualImport/ManualImportModule.cs b/src/NzbDrone.Api/ManualImport/ManualImportModule.cs index 769f1434c..5b46a1604 100644 --- a/src/NzbDrone.Api/ManualImport/ManualImportModule.cs +++ b/src/NzbDrone.Api/ManualImport/ManualImportModule.cs @@ -1,11 +1,13 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using NzbDrone.Core.MediaFiles.MovieImport.Manual; using NzbDrone.Core.Qualities; +using Radarr.Http; +using Radarr.Http.Extensions; namespace NzbDrone.Api.ManualImport { - public class ManualImportModule : NzbDroneRestModule + public class ManualImportModule : RadarrRestModule { private readonly IManualImportService _manualImportService; @@ -24,8 +26,9 @@ namespace NzbDrone.Api.ManualImport var downloadIdQuery = Request.Query.downloadId; var downloadId = (string)downloadIdQuery.Value; + var filterExistingFiles = Request.GetBooleanQueryParameter("filterExistingFiles", true); - return _manualImportService.GetMediaFiles(folder, downloadId).ToResource().Select(AddQualityWeight).ToList(); + return _manualImportService.GetMediaFiles(folder, downloadId, filterExistingFiles).ToResource().Select(AddQualityWeight).ToList(); } private ManualImportResource AddQualityWeight(ManualImportResource item) diff --git a/src/NzbDrone.Api/ManualImport/ManualImportResource.cs b/src/NzbDrone.Api/ManualImport/ManualImportResource.cs index eee878cdf..fea7987b8 100644 --- a/src/NzbDrone.Api/ManualImport/ManualImportResource.cs +++ b/src/NzbDrone.Api/ManualImport/ManualImportResource.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; using NzbDrone.Api.Movies; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Common.Crypto; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Qualities; diff --git a/src/NzbDrone.Api/MovieFiles/MovieFileModule.cs b/src/NzbDrone.Api/MovieFiles/MovieFileModule.cs index 049f61104..8d1a28754 100644 --- a/src/NzbDrone.Api/MovieFiles/MovieFileModule.cs +++ b/src/NzbDrone.Api/MovieFiles/MovieFileModule.cs @@ -1,7 +1,8 @@ using System.Collections.Generic; using System.IO; using NLog; -using NzbDrone.Api.REST; +using Radarr.Http; +using Radarr.Http.REST; using NzbDrone.Core.Datastore.Events; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles.Events; @@ -12,7 +13,7 @@ using NzbDrone.SignalR; namespace NzbDrone.Api.MovieFiles { - public class MovieFileModule : NzbDroneRestModuleWithSignalR, IHandle + public class MovieFileModule : RadarrRestModuleWithSignalR, IHandle { private readonly IMediaFileService _mediaFileService; private readonly IRecycleBinProvider _recycleBinProvider; diff --git a/src/NzbDrone.Api/MovieFiles/MovieFileResource.cs b/src/NzbDrone.Api/MovieFiles/MovieFileResource.cs index 209323966..711013e7d 100644 --- a/src/NzbDrone.Api/MovieFiles/MovieFileResource.cs +++ b/src/NzbDrone.Api/MovieFiles/MovieFileResource.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Api.Movies; using NzbDrone.Core.Qualities; using NzbDrone.Core.MediaFiles; diff --git a/src/NzbDrone.Api/Movies/AlternativeTitleModule.cs b/src/NzbDrone.Api/Movies/AlternativeTitleModule.cs index d5192e2d6..8847346c0 100644 --- a/src/NzbDrone.Api/Movies/AlternativeTitleModule.cs +++ b/src/NzbDrone.Api/Movies/AlternativeTitleModule.cs @@ -16,10 +16,11 @@ using NzbDrone.Core.Movies.AlternativeTitles; using NzbDrone.Core.RootFolders; using NzbDrone.Core.Movies; using NzbDrone.Core.Movies.Events; +using Radarr.Http; namespace NzbDrone.Api.Movies { - public class AlternativeTitleModule : NzbDroneRestModule + public class AlternativeTitleModule : RadarrRestModule { private readonly IAlternativeTitleService _altTitleService; private readonly IMovieService _movieService; diff --git a/src/NzbDrone.Api/Movies/AlternativeTitleResource.cs b/src/NzbDrone.Api/Movies/AlternativeTitleResource.cs index b3bc26930..c5aeed2ca 100644 --- a/src/NzbDrone.Api/Movies/AlternativeTitleResource.cs +++ b/src/NzbDrone.Api/Movies/AlternativeTitleResource.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.MediaCover; using NzbDrone.Core.Movies; using NzbDrone.Core.Qualities; diff --git a/src/NzbDrone.Api/Movies/AlternativeYearModule.cs b/src/NzbDrone.Api/Movies/AlternativeYearModule.cs index 598d0e14b..eb40041b4 100644 --- a/src/NzbDrone.Api/Movies/AlternativeYearModule.cs +++ b/src/NzbDrone.Api/Movies/AlternativeYearModule.cs @@ -17,10 +17,11 @@ using NzbDrone.Core.Movies.AlternativeTitles; using NzbDrone.Core.RootFolders; using NzbDrone.Core.Movies; using NzbDrone.Core.Movies.Events; +using Radarr.Http; namespace NzbDrone.Api.Movies { - public class AlternativeYearModule : NzbDroneRestModule + public class AlternativeYearModule : RadarrRestModule { private readonly IMovieService _movieService; private readonly IRadarrAPIClient _radarrApi; diff --git a/src/NzbDrone.Api/Movies/AlternativeYearResource.cs b/src/NzbDrone.Api/Movies/AlternativeYearResource.cs index 6e3ebf787..cef2d7dea 100644 --- a/src/NzbDrone.Api/Movies/AlternativeYearResource.cs +++ b/src/NzbDrone.Api/Movies/AlternativeYearResource.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.MediaCover; using NzbDrone.Core.Movies; using NzbDrone.Core.Qualities; diff --git a/src/NzbDrone.Api/Movies/FetchMovieListModule.cs b/src/NzbDrone.Api/Movies/FetchMovieListModule.cs index a1580460d..953a9bd27 100644 --- a/src/NzbDrone.Api/Movies/FetchMovieListModule.cs +++ b/src/NzbDrone.Api/Movies/FetchMovieListModule.cs @@ -1,14 +1,15 @@ using System.Collections.Generic; using Nancy; -using NzbDrone.Api.Extensions; using NzbDrone.Core.MediaCover; using NzbDrone.Core.MetadataSource; using System.Linq; using NzbDrone.Core.NetImport; +using Radarr.Http; +using Radarr.Http.Extensions; namespace NzbDrone.Api.Movies { - public class FetchMovieListModule : NzbDroneRestModule + public class FetchMovieListModule : RadarrRestModule { private readonly IFetchNetImport _fetchNetImport; private readonly ISearchForNewMovie _movieSearch; diff --git a/src/NzbDrone.Api/Movies/MovieBulkImportModule.cs b/src/NzbDrone.Api/Movies/MovieBulkImportModule.cs index 6e958f1f6..977cdeba8 100644 --- a/src/NzbDrone.Api/Movies/MovieBulkImportModule.cs +++ b/src/NzbDrone.Api/Movies/MovieBulkImportModule.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using Nancy; -using NzbDrone.Api.Extensions; +using Radarr.Http.Extensions; using NzbDrone.Core.MediaCover; using NzbDrone.Core.MetadataSource; using NzbDrone.Core.Parser; @@ -15,6 +15,7 @@ using NzbDrone.Core.RootFolders; using NzbDrone.Common.Cache; using NzbDrone.Core.Movies; using NzbDrone.Core.Profiles; +using Radarr.Http; namespace NzbDrone.Api.Movies { @@ -27,7 +28,7 @@ namespace NzbDrone.Api.Movies } } - public class MovieBulkImportModule : NzbDroneRestModule + public class MovieBulkImportModule : RadarrRestModule { private readonly ISearchForNewMovie _searchProxy; private readonly IRootFolderService _rootFolderService; diff --git a/src/NzbDrone.Api/Movies/MovieDiscoverModule.cs b/src/NzbDrone.Api/Movies/MovieDiscoverModule.cs index 7decab287..40db69bda 100644 --- a/src/NzbDrone.Api/Movies/MovieDiscoverModule.cs +++ b/src/NzbDrone.Api/Movies/MovieDiscoverModule.cs @@ -1,17 +1,17 @@ using System.Collections.Generic; using Nancy; -using NzbDrone.Api.Extensions; +using Radarr.Http.Extensions; using NzbDrone.Core.MediaCover; using NzbDrone.Core.MetadataSource; using System.Linq; using System; -using NzbDrone.Api.REST; +using Radarr.Http; using NzbDrone.Core.NetImport; using NzbDrone.Api.NetImport; namespace NzbDrone.Api.Movies { - public class MovieDiscoverModule : NzbDroneRestModule + public class MovieDiscoverModule : RadarrRestModule { private readonly IDiscoverNewMovies _searchProxy; private readonly INetImportFactory _netImportFactory; diff --git a/src/NzbDrone.Api/Movies/MovieEditorModule.cs b/src/NzbDrone.Api/Movies/MovieEditorModule.cs index db90a3f95..db7721fcf 100644 --- a/src/NzbDrone.Api/Movies/MovieEditorModule.cs +++ b/src/NzbDrone.Api/Movies/MovieEditorModule.cs @@ -3,9 +3,10 @@ using System.Collections.Generic; using System.Linq; using Nancy; using Nancy.Responses; -using NzbDrone.Api.Extensions; -using NzbDrone.Api.REST; +using Radarr.Http.Extensions; +using Radarr.Http.REST; using NzbDrone.Core.Movies; +using Radarr.Http.Mapping; namespace NzbDrone.Api.Movies { diff --git a/src/NzbDrone.Api/Movies/MovieLookupModule.cs b/src/NzbDrone.Api/Movies/MovieLookupModule.cs index 1801f90dc..a2f02c545 100644 --- a/src/NzbDrone.Api/Movies/MovieLookupModule.cs +++ b/src/NzbDrone.Api/Movies/MovieLookupModule.cs @@ -1,15 +1,16 @@ using System.Collections.Generic; using Nancy; -using NzbDrone.Api.Extensions; +using Radarr.Http.Extensions; using NzbDrone.Core.MediaCover; using NzbDrone.Core.MetadataSource; using System.Linq; using System; -using NzbDrone.Api.REST; +using Radarr.Http; +using Radarr.Http.REST; namespace NzbDrone.Api.Movies { - public class MovieLookupModule : NzbDroneRestModule + public class MovieLookupModule : RadarrRestModule { private readonly ISearchForNewMovie _searchProxy; private readonly IProvideMovieInfo _movieInfo; diff --git a/src/NzbDrone.Api/Movies/MovieModule.cs b/src/NzbDrone.Api/Movies/MovieModule.cs index fb7538f20..db9f6910d 100644 --- a/src/NzbDrone.Api/Movies/MovieModule.cs +++ b/src/NzbDrone.Api/Movies/MovieModule.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using FluentValidation; using NzbDrone.Common.Extensions; -using NzbDrone.Api.Extensions; +using Radarr.Http.Extensions; using NzbDrone.Core.Datastore.Events; using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaFiles; @@ -17,10 +17,11 @@ using NzbDrone.SignalR; using NzbDrone.Core.Datastore; using Microsoft.CSharp.RuntimeBinder; using Nancy; +using Radarr.Http; namespace NzbDrone.Api.Movies { - public class MovieModule : NzbDroneRestModuleWithSignalR, + public class MovieModule : RadarrRestModuleWithSignalR, IHandle, IHandle, IHandle, @@ -41,8 +42,8 @@ namespace NzbDrone.Api.Movies RootFolderValidator rootFolderValidator, MoviePathValidator moviesPathValidator, MovieExistsValidator moviesExistsValidator, - DroneFactoryValidator droneFactoryValidator, MovieAncestorValidator moviesAncestorValidator, + SystemFolderValidator systemFolderValidator, ProfileExistsValidator profileExistsValidator ) : base(signalRBroadcaster) @@ -64,15 +65,15 @@ namespace NzbDrone.Api.Movies UpdateResource = UpdateMovie; DeleteResource = DeleteMovie; - Validation.RuleBuilderExtensions.ValidId(SharedValidator.RuleFor(s => s.ProfileId)); + SharedValidator.RuleFor(s => s.ProfileId).ValidId(); SharedValidator.RuleFor(s => s.Path) .Cascade(CascadeMode.StopOnFirstFailure) .IsValidPath() .SetValidator(rootFolderValidator) .SetValidator(moviesPathValidator) - .SetValidator(droneFactoryValidator) .SetValidator(moviesAncestorValidator) + .SetValidator(systemFolderValidator) .When(s => !s.Path.IsNullOrWhiteSpace()); SharedValidator.RuleFor(s => s.ProfileId).SetValidator(profileExistsValidator); @@ -110,14 +111,14 @@ namespace NzbDrone.Api.Movies private PagingResource GetMoviePaged(PagingResource pagingResource) { - var pagingSpec = pagingResource.MapToPagingSpec(); + var pagingSpec = pagingResource.MapToPagingSpec(); - pagingSpec.FilterExpression = _moviesService.ConstructFilterExpression(pagingResource.FilterKey, pagingResource.FilterValue, pagingResource.FilterType); + pagingSpec.FilterExpressions.Add(_moviesService.ConstructFilterExpression(pagingResource.Filters.FirstOrDefault().Key, pagingResource.Filters.FirstOrDefault().Value)); return ApplyToPage(_moviesService.Paged, pagingSpec, MapToResource); } - protected MovieResource MapToResource(Core.Movies.Movie movies) + protected MovieResource MapToResource(Movie movies) { if (movies == null) return null; diff --git a/src/NzbDrone.Api/Movies/MovieModuleWithSignalR.cs b/src/NzbDrone.Api/Movies/MovieModuleWithSignalR.cs index 2a59157c9..30c693b5d 100644 --- a/src/NzbDrone.Api/Movies/MovieModuleWithSignalR.cs +++ b/src/NzbDrone.Api/Movies/MovieModuleWithSignalR.cs @@ -6,10 +6,11 @@ using NzbDrone.Core.MediaFiles.Events; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Movies; using NzbDrone.SignalR; +using Radarr.Http; namespace NzbDrone.Api.Movies { - public abstract class MovieModuleWithSignalR : NzbDroneRestModuleWithSignalR, + public abstract class MovieModuleWithSignalR : RadarrRestModuleWithSignalR, IHandle, IHandle { diff --git a/src/NzbDrone.Api/Movies/MovieResource.cs b/src/NzbDrone.Api/Movies/MovieResource.cs index 3024b4c00..c89b08e26 100644 --- a/src/NzbDrone.Api/Movies/MovieResource.cs +++ b/src/NzbDrone.Api/Movies/MovieResource.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.MediaCover; using NzbDrone.Core.Movies; using NzbDrone.Api.MovieFiles; diff --git a/src/NzbDrone.Api/Movies/RenameMovieModule.cs b/src/NzbDrone.Api/Movies/RenameMovieModule.cs index e965545c5..cdbb07e83 100644 --- a/src/NzbDrone.Api/Movies/RenameMovieModule.cs +++ b/src/NzbDrone.Api/Movies/RenameMovieModule.cs @@ -1,13 +1,14 @@ -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.MediaFiles; using System; using System.Collections.Generic; using System.Linq; using System.Text; +using Radarr.Http; namespace NzbDrone.Api.Movies { - public class RenameMovieModule : NzbDroneRestModule + public class RenameMovieModule : RadarrRestModule { private readonly IRenameMovieFileService _renameMovieFileService; diff --git a/src/NzbDrone.Api/Movies/RenameMovieResource.cs b/src/NzbDrone.Api/Movies/RenameMovieResource.cs index 04eeef97c..a95b58fa4 100644 --- a/src/NzbDrone.Api/Movies/RenameMovieResource.cs +++ b/src/NzbDrone.Api/Movies/RenameMovieResource.cs @@ -1,4 +1,4 @@ -using NzbDrone.Api.REST; +using Radarr.Http.REST; using System.Collections.Generic; using System.Linq; diff --git a/src/NzbDrone.Api/NetImport/ImportExclusionsModule.cs b/src/NzbDrone.Api/NetImport/ImportExclusionsModule.cs index 4615c65f7..33a396998 100644 --- a/src/NzbDrone.Api/NetImport/ImportExclusionsModule.cs +++ b/src/NzbDrone.Api/NetImport/ImportExclusionsModule.cs @@ -1,13 +1,14 @@ using System.Collections.Generic; using FluentValidation; -using NzbDrone.Api.ClientSchema; +using Radarr.Http.ClientSchema; using NzbDrone.Core.NetImport; using NzbDrone.Core.NetImport.ImportExclusions; using NzbDrone.Core.Validation.Paths; +using Radarr.Http; namespace NzbDrone.Api.NetImport { - public class ImportExclusionsModule : NzbDroneRestModule + public class ImportExclusionsModule : RadarrRestModule { private readonly IImportExclusionsService _exclusionService; diff --git a/src/NzbDrone.Api/NetImport/ListImportModule.cs b/src/NzbDrone.Api/NetImport/ListImportModule.cs index ccbe48119..78c0fc538 100644 --- a/src/NzbDrone.Api/NetImport/ListImportModule.cs +++ b/src/NzbDrone.Api/NetImport/ListImportModule.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using Nancy; using Nancy.Extensions; -using NzbDrone.Api.Extensions; +using Radarr.Http.Extensions; using NzbDrone.Api.Movies; using NzbDrone.Core.MetadataSource; using NzbDrone.Core.Movies; diff --git a/src/NzbDrone.Api/NetImport/NetImportModule.cs b/src/NzbDrone.Api/NetImport/NetImportModule.cs index a382e5183..55132adda 100644 --- a/src/NzbDrone.Api/NetImport/NetImportModule.cs +++ b/src/NzbDrone.Api/NetImport/NetImportModule.cs @@ -1,5 +1,5 @@ -using FluentValidation; -using NzbDrone.Api.ClientSchema; +using FluentValidation; +using Radarr.Http.ClientSchema; using NzbDrone.Core.NetImport; using NzbDrone.Core.Validation.Paths; diff --git a/src/NzbDrone.Api/NzbDrone.Api.csproj b/src/NzbDrone.Api/NzbDrone.Api.csproj index 7d6ccef8d..4e98d5e31 100644 --- a/src/NzbDrone.Api/NzbDrone.Api.csproj +++ b/src/NzbDrone.Api/NzbDrone.Api.csproj @@ -8,7 +8,7 @@ Library Properties NzbDrone.Api - NzbDrone.Api + Radarr.Api v4.6.1 512 ..\ @@ -91,31 +91,15 @@ Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - - - @@ -164,31 +148,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - @@ -206,14 +165,10 @@ - - - - @@ -228,24 +183,15 @@ - - - - - - - - - @@ -253,13 +199,8 @@ - - - - - @@ -290,6 +231,10 @@ {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36} NzbDrone.SignalR + + {c5953dab-89db-46d9-a401-d620f54b776e} + Radarr.Http + diff --git a/src/NzbDrone.Api/NzbDroneRestModuleWithSignalR.cs b/src/NzbDrone.Api/NzbDroneRestModuleWithSignalR.cs deleted file mode 100644 index a2061a770..000000000 --- a/src/NzbDrone.Api/NzbDroneRestModuleWithSignalR.cs +++ /dev/null @@ -1,66 +0,0 @@ -using NzbDrone.Api.REST; -using NzbDrone.Core.Datastore; -using NzbDrone.Core.Datastore.Events; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.SignalR; - -namespace NzbDrone.Api -{ - public abstract class NzbDroneRestModuleWithSignalR : NzbDroneRestModule, IHandle> - where TResource : RestResource, new() - where TModel : ModelBase, new() - { - private readonly IBroadcastSignalRMessage _signalRBroadcaster; - - protected NzbDroneRestModuleWithSignalR(IBroadcastSignalRMessage signalRBroadcaster) - { - _signalRBroadcaster = signalRBroadcaster; - } - - protected NzbDroneRestModuleWithSignalR(IBroadcastSignalRMessage signalRBroadcaster, string resource) - : base(resource) - { - _signalRBroadcaster = signalRBroadcaster; - } - - public void Handle(ModelEvent message) - { - if (message.Action == ModelAction.Deleted || message.Action == ModelAction.Sync) - { - BroadcastResourceChange(message.Action); - } - - BroadcastResourceChange(message.Action, message.Model.Id); - } - - protected void BroadcastResourceChange(ModelAction action, int id) - { - var resource = GetResourceById(id); - BroadcastResourceChange(action, resource); - } - - - protected void BroadcastResourceChange(ModelAction action, TResource resource) - { - var signalRMessage = new SignalRMessage - { - Name = Resource, - Body = new ResourceChangeMessage(resource, action) - }; - - _signalRBroadcaster.BroadcastMessage(signalRMessage); - } - - - protected void BroadcastResourceChange(ModelAction action) - { - var signalRMessage = new SignalRMessage - { - Name = Resource, - Body = new ResourceChangeMessage(action) - }; - - _signalRBroadcaster.BroadcastMessage(signalRMessage); - } - } -} \ No newline at end of file diff --git a/src/NzbDrone.Api/Parse/ParseModule.cs b/src/NzbDrone.Api/Parse/ParseModule.cs index 20bdd8cfd..6b96c9f75 100644 --- a/src/NzbDrone.Api/Parse/ParseModule.cs +++ b/src/NzbDrone.Api/Parse/ParseModule.cs @@ -1,10 +1,11 @@ using System.Collections.Generic; using NzbDrone.Api.Movies; using NzbDrone.Core.Parser; +using Radarr.Http; namespace NzbDrone.Api.Parse { - public class ParseModule : NzbDroneRestModule + public class ParseModule : RadarrRestModule { private readonly IParsingService _parsingService; diff --git a/src/NzbDrone.Api/Parse/ParseResource.cs b/src/NzbDrone.Api/Parse/ParseResource.cs index de0dbcc2c..3bc3481f8 100644 --- a/src/NzbDrone.Api/Parse/ParseResource.cs +++ b/src/NzbDrone.Api/Parse/ParseResource.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using NzbDrone.Api.Movies; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Api.Parse diff --git a/src/NzbDrone.Api/Profiles/Delay/DelayProfileModule.cs b/src/NzbDrone.Api/Profiles/Delay/DelayProfileModule.cs index e7975b661..8ccc3fd84 100644 --- a/src/NzbDrone.Api/Profiles/Delay/DelayProfileModule.cs +++ b/src/NzbDrone.Api/Profiles/Delay/DelayProfileModule.cs @@ -1,13 +1,14 @@ -using System.Collections.Generic; +using System.Collections.Generic; using FluentValidation; using FluentValidation.Results; -using NzbDrone.Api.REST; -using NzbDrone.Api.Validation; +using Radarr.Http.REST; +using Radarr.Http.Validation; using NzbDrone.Core.Profiles.Delay; +using Radarr.Http; namespace NzbDrone.Api.Profiles.Delay { - public class DelayProfileModule : NzbDroneRestModule + public class DelayProfileModule : RadarrRestModule { private readonly IDelayProfileService _delayProfileService; @@ -72,4 +73,4 @@ namespace NzbDrone.Api.Profiles.Delay return _delayProfileService.All().ToResource(); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Profiles/Delay/DelayProfileResource.cs b/src/NzbDrone.Api/Profiles/Delay/DelayProfileResource.cs index e35df9043..a626c220a 100644 --- a/src/NzbDrone.Api/Profiles/Delay/DelayProfileResource.cs +++ b/src/NzbDrone.Api/Profiles/Delay/DelayProfileResource.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Indexers; using NzbDrone.Core.Profiles.Delay; diff --git a/src/NzbDrone.Api/Profiles/Languages/LanguageModule.cs b/src/NzbDrone.Api/Profiles/Languages/LanguageModule.cs index 147bc69aa..9bbeada21 100644 --- a/src/NzbDrone.Api/Profiles/Languages/LanguageModule.cs +++ b/src/NzbDrone.Api/Profiles/Languages/LanguageModule.cs @@ -1,11 +1,12 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using NzbDrone.Core.Parser; +using Radarr.Http; namespace NzbDrone.Api.Profiles.Languages { - public class LanguageModule : NzbDroneRestModule + public class LanguageModule : RadarrRestModule { public LanguageModule() { @@ -36,4 +37,4 @@ namespace NzbDrone.Api.Profiles.Languages .ToList(); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Profiles/Languages/LanguageResource.cs b/src/NzbDrone.Api/Profiles/Languages/LanguageResource.cs index 09e5ba28c..ae68f2742 100644 --- a/src/NzbDrone.Api/Profiles/Languages/LanguageResource.cs +++ b/src/NzbDrone.Api/Profiles/Languages/LanguageResource.cs @@ -1,5 +1,5 @@ using Newtonsoft.Json; -using NzbDrone.Api.REST; +using Radarr.Http.REST; namespace NzbDrone.Api.Profiles.Languages { diff --git a/src/NzbDrone.Api/Profiles/ProfileModule.cs b/src/NzbDrone.Api/Profiles/ProfileModule.cs index ed8c5c9bf..554bcf991 100644 --- a/src/NzbDrone.Api/Profiles/ProfileModule.cs +++ b/src/NzbDrone.Api/Profiles/ProfileModule.cs @@ -1,14 +1,16 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using FluentValidation; using NzbDrone.Common.Extensions; using NzbDrone.Core.CustomFormats; using NzbDrone.Core.Profiles; using NzbDrone.Core.Validation; +using Radarr.Http; +using Radarr.Http.Mapping; namespace NzbDrone.Api.Profiles { - public class ProfileModule : NzbDroneRestModule + public class ProfileModule : RadarrRestModule { private readonly IProfileService _profileService; private readonly ICustomFormatService _formatService; diff --git a/src/NzbDrone.Api/Profiles/ProfileResource.cs b/src/NzbDrone.Api/Profiles/ProfileResource.cs index 114131238..8bd0b1902 100644 --- a/src/NzbDrone.Api/Profiles/ProfileResource.cs +++ b/src/NzbDrone.Api/Profiles/ProfileResource.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; - using NzbDrone.Api.Qualities; - using NzbDrone.Api.REST; +using NzbDrone.Api.Qualities; +using Radarr.Http.REST; using NzbDrone.Core.Parser; using NzbDrone.Core.Profiles; using NzbDrone.Core.Qualities; diff --git a/src/NzbDrone.Api/Profiles/ProfileSchemaModule.cs b/src/NzbDrone.Api/Profiles/ProfileSchemaModule.cs index b61431798..cfa9dbdb1 100644 --- a/src/NzbDrone.Api/Profiles/ProfileSchemaModule.cs +++ b/src/NzbDrone.Api/Profiles/ProfileSchemaModule.cs @@ -1,13 +1,15 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; - using NzbDrone.Core.CustomFormats; - using NzbDrone.Core.Parser; +using NzbDrone.Core.CustomFormats; +using NzbDrone.Core.Parser; using NzbDrone.Core.Profiles; using NzbDrone.Core.Qualities; +using Radarr.Http; +using Radarr.Http.Mapping; namespace NzbDrone.Api.Profiles { - public class ProfileSchemaModule : NzbDroneRestModule + public class ProfileSchemaModule : RadarrRestModule { private readonly IQualityDefinitionService _qualityDefinitionService; private readonly ICustomFormatService _formatService; diff --git a/src/NzbDrone.Api/Properties/AssemblyInfo.cs b/src/NzbDrone.Api/Properties/AssemblyInfo.cs index 300ee6fc1..aad3f0395 100644 --- a/src/NzbDrone.Api/Properties/AssemblyInfo.cs +++ b/src/NzbDrone.Api/Properties/AssemblyInfo.cs @@ -2,9 +2,9 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -[assembly: AssemblyTitle("NzbDrone.Api")] +[assembly: AssemblyTitle("Radarr.Api")] [assembly: Guid("4c0922d7-979e-4ff7-b44b-b8ac2100eeb5")] -[assembly: InternalsVisibleTo("NzbDrone.Core")] +[assembly: InternalsVisibleTo("Radarr.Core")] diff --git a/src/NzbDrone.Api/ProviderModuleBase.cs b/src/NzbDrone.Api/ProviderModuleBase.cs index c62e55d21..c7a09ea05 100644 --- a/src/NzbDrone.Api/ProviderModuleBase.cs +++ b/src/NzbDrone.Api/ProviderModuleBase.cs @@ -1,18 +1,20 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using FluentValidation; using FluentValidation.Results; using Nancy; -using NzbDrone.Api.ClientSchema; -using NzbDrone.Api.Extensions; +using Radarr.Http.Extensions; using NzbDrone.Common.Reflection; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; using Newtonsoft.Json; +using Radarr.Http; +using Radarr.Http.ClientSchema; +using Radarr.Http.Mapping; namespace NzbDrone.Api { - public abstract class ProviderModuleBase : NzbDroneRestModule + public abstract class ProviderModuleBase : RadarrRestModule where TProviderDefinition : ProviderDefinition, new() where TProvider : IProvider where TProviderResource : ProviderResource, new() diff --git a/src/NzbDrone.Api/ProviderResource.cs b/src/NzbDrone.Api/ProviderResource.cs index 9927a09cc..cfa016b55 100644 --- a/src/NzbDrone.Api/ProviderResource.cs +++ b/src/NzbDrone.Api/ProviderResource.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; -using NzbDrone.Api.ClientSchema; -using NzbDrone.Api.REST; +using System.Collections.Generic; +using Radarr.Http.ClientSchema; +using Radarr.Http.REST; using NzbDrone.Core.ThingiProvider; namespace NzbDrone.Api @@ -17,4 +17,4 @@ namespace NzbDrone.Api public List Presets { get; set; } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Qualities/CustomFormatModule.cs b/src/NzbDrone.Api/Qualities/CustomFormatModule.cs index 8a4cb7c24..a128c626b 100644 --- a/src/NzbDrone.Api/Qualities/CustomFormatModule.cs +++ b/src/NzbDrone.Api/Qualities/CustomFormatModule.cs @@ -1,15 +1,16 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using FluentValidation; using Nancy; -using NzbDrone.Api.Extensions; -using NzbDrone.Api.Validation; +using Radarr.Http.Extensions; +using Radarr.Http.Validation; using NzbDrone.Core.CustomFormats; using NzbDrone.Core.Parser; +using Radarr.Http; namespace NzbDrone.Api.Qualities { - public class CustomFormatModule : NzbDroneRestModule + public class CustomFormatModule : RadarrRestModule { private readonly ICustomFormatService _formatService; private readonly IParsingService _parsingService; @@ -22,7 +23,7 @@ namespace NzbDrone.Api.Qualities SharedValidator.RuleFor(c => c.Name).NotEmpty(); SharedValidator.RuleFor(c => c.Name) .Must((v, c) => !_formatService.All().Any(f => f.Name == c && f.Id != v.Id)).WithMessage("Must be unique."); - SharedValidator.RuleFor(c => c.FormatTags).AreValidFormatTags(); + SharedValidator.RuleFor(c => c.FormatTags).SetValidator(new FormatTagValidator()); SharedValidator.RuleFor(c => c.FormatTags).Must((v, c) => { var allFormats = _formatService.All(); diff --git a/src/NzbDrone.Api/Qualities/CustomFormatResource.cs b/src/NzbDrone.Api/Qualities/CustomFormatResource.cs index bfb501090..1d0511d47 100644 --- a/src/NzbDrone.Api/Qualities/CustomFormatResource.cs +++ b/src/NzbDrone.Api/Qualities/CustomFormatResource.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.CustomFormats; namespace NzbDrone.Api.Qualities diff --git a/src/NzbDrone.Api/Qualities/FormatTagMatchResultResource.cs b/src/NzbDrone.Api/Qualities/FormatTagMatchResultResource.cs index 96ee5f8f6..cad3c78d1 100644 --- a/src/NzbDrone.Api/Qualities/FormatTagMatchResultResource.cs +++ b/src/NzbDrone.Api/Qualities/FormatTagMatchResultResource.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Common.Extensions; using NzbDrone.Core.CustomFormats; using NzbDrone.Core.Qualities; diff --git a/src/NzbDrone.Api/Qualities/QualityDefinitionModule.cs b/src/NzbDrone.Api/Qualities/QualityDefinitionModule.cs index acb469218..cda3676ae 100644 --- a/src/NzbDrone.Api/Qualities/QualityDefinitionModule.cs +++ b/src/NzbDrone.Api/Qualities/QualityDefinitionModule.cs @@ -1,13 +1,14 @@ -using System; +using System; using System.Collections.Generic; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; +using Radarr.Http; namespace NzbDrone.Api.Qualities { - public class QualityDefinitionModule : NzbDroneRestModule + public class QualityDefinitionModule : RadarrRestModule { private readonly IQualityDefinitionService _qualityDefinitionService; private readonly IParsingService _parsingService; diff --git a/src/NzbDrone.Api/Qualities/QualityDefinitionResource.cs b/src/NzbDrone.Api/Qualities/QualityDefinitionResource.cs index f98f56ef6..a795e7697 100644 --- a/src/NzbDrone.Api/Qualities/QualityDefinitionResource.cs +++ b/src/NzbDrone.Api/Qualities/QualityDefinitionResource.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Qualities; namespace NzbDrone.Api.Qualities diff --git a/src/NzbDrone.Api/Queue/QueueActionModule.cs b/src/NzbDrone.Api/Queue/QueueActionModule.cs index 5971d9b97..ac7531a9e 100644 --- a/src/NzbDrone.Api/Queue/QueueActionModule.cs +++ b/src/NzbDrone.Api/Queue/QueueActionModule.cs @@ -1,16 +1,17 @@ -using System; +using System; using Nancy; using Nancy.Responses; -using NzbDrone.Api.Extensions; -using NzbDrone.Api.REST; +using Radarr.Http.Extensions; +using Radarr.Http.REST; using NzbDrone.Core.Download; using NzbDrone.Core.Download.Pending; using NzbDrone.Core.Download.TrackedDownloads; using NzbDrone.Core.Queue; +using Radarr.Http; namespace NzbDrone.Api.Queue { - public class QueueActionModule : NzbDroneRestModule + public class QueueActionModule : RadarrRestModule { private readonly IQueueService _queueService; private readonly ITrackedDownloadService _trackedDownloadService; diff --git a/src/NzbDrone.Api/Queue/QueueModule.cs b/src/NzbDrone.Api/Queue/QueueModule.cs index 00e614132..95ad3194d 100644 --- a/src/NzbDrone.Api/Queue/QueueModule.cs +++ b/src/NzbDrone.Api/Queue/QueueModule.cs @@ -1,14 +1,15 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using NzbDrone.Core.Datastore.Events; using NzbDrone.Core.Download.Pending; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Queue; using NzbDrone.SignalR; +using Radarr.Http; namespace NzbDrone.Api.Queue { - public class QueueModule : NzbDroneRestModuleWithSignalR, + public class QueueModule : RadarrRestModuleWithSignalR, IHandle, IHandle { private readonly IQueueService _queueService; @@ -45,4 +46,4 @@ namespace NzbDrone.Api.Queue BroadcastResourceChange(ModelAction.Sync); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Queue/QueueResource.cs b/src/NzbDrone.Api/Queue/QueueResource.cs index ea82956ad..eafe50794 100644 --- a/src/NzbDrone.Api/Queue/QueueResource.cs +++ b/src/NzbDrone.Api/Queue/QueueResource.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Qualities; using NzbDrone.Api.Movies; using NzbDrone.Core.Download.TrackedDownloads; diff --git a/src/NzbDrone.Api/RemotePathMappings/RemotePathMappingModule.cs b/src/NzbDrone.Api/RemotePathMappings/RemotePathMappingModule.cs index a61b5f7b3..23bdcc66a 100644 --- a/src/NzbDrone.Api/RemotePathMappings/RemotePathMappingModule.cs +++ b/src/NzbDrone.Api/RemotePathMappings/RemotePathMappingModule.cs @@ -1,11 +1,12 @@ -using System.Collections.Generic; +using System.Collections.Generic; using FluentValidation; using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.Validation.Paths; +using Radarr.Http; namespace NzbDrone.Api.RemotePathMappings { - public class RemotePathMappingModule : NzbDroneRestModule + public class RemotePathMappingModule : RadarrRestModule { private readonly IRemotePathMappingService _remotePathMappingService; @@ -64,4 +65,4 @@ namespace NzbDrone.Api.RemotePathMappings _remotePathMappingService.Update(mapping); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/RemotePathMappings/RemotePathMappingResource.cs b/src/NzbDrone.Api/RemotePathMappings/RemotePathMappingResource.cs index 60c01b682..c52774bae 100644 --- a/src/NzbDrone.Api/RemotePathMappings/RemotePathMappingResource.cs +++ b/src/NzbDrone.Api/RemotePathMappings/RemotePathMappingResource.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.RemotePathMappings; namespace NzbDrone.Api.RemotePathMappings diff --git a/src/NzbDrone.Api/Restrictions/RestrictionModule.cs b/src/NzbDrone.Api/Restrictions/RestrictionModule.cs index 918b3a50b..ab00cca13 100644 --- a/src/NzbDrone.Api/Restrictions/RestrictionModule.cs +++ b/src/NzbDrone.Api/Restrictions/RestrictionModule.cs @@ -1,11 +1,12 @@ -using System.Collections.Generic; +using System.Collections.Generic; using FluentValidation.Results; using NzbDrone.Common.Extensions; using NzbDrone.Core.Restrictions; +using Radarr.Http; -namespace NzbDrone.Api.Restrictions +namespace Radarr.Http.RESTrictions { - public class RestrictionModule : NzbDroneRestModule + public class RestrictionModule : RadarrRestModule { private readonly IRestrictionService _restrictionService; diff --git a/src/NzbDrone.Api/Restrictions/RestrictionResource.cs b/src/NzbDrone.Api/Restrictions/RestrictionResource.cs index 14085e820..a2d9d9424 100644 --- a/src/NzbDrone.Api/Restrictions/RestrictionResource.cs +++ b/src/NzbDrone.Api/Restrictions/RestrictionResource.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Linq; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Restrictions; -namespace NzbDrone.Api.Restrictions +namespace Radarr.Http.RESTrictions { public class RestrictionResource : RestResource { diff --git a/src/NzbDrone.Api/RootFolders/RootFolderModule.cs b/src/NzbDrone.Api/RootFolders/RootFolderModule.cs index 30bfcc635..5492bc533 100644 --- a/src/NzbDrone.Api/RootFolders/RootFolderModule.cs +++ b/src/NzbDrone.Api/RootFolders/RootFolderModule.cs @@ -1,12 +1,14 @@ -using System.Collections.Generic; +using System.Collections.Generic; using FluentValidation; using NzbDrone.Core.RootFolders; using NzbDrone.Core.Validation.Paths; using NzbDrone.SignalR; +using Radarr.Http; +using Radarr.Http.Mapping; namespace NzbDrone.Api.RootFolders { - public class RootFolderModule : NzbDroneRestModuleWithSignalR + public class RootFolderModule : RadarrRestModuleWithSignalR { private readonly IRootFolderService _rootFolderService; @@ -14,9 +16,9 @@ namespace NzbDrone.Api.RootFolders IBroadcastSignalRMessage signalRBroadcaster, RootFolderValidator rootFolderValidator, PathExistsValidator pathExistsValidator, - DroneFactoryValidator droneFactoryValidator, MappedNetworkDriveValidator mappedNetworkDriveValidator, StartupFolderValidator startupFolderValidator, + SystemFolderValidator systemFolderValidator, FolderWritableValidator folderWritableValidator) : base(signalRBroadcaster) { @@ -31,10 +33,10 @@ namespace NzbDrone.Api.RootFolders .Cascade(CascadeMode.StopOnFirstFailure) .IsValidPath() .SetValidator(rootFolderValidator) - .SetValidator(droneFactoryValidator) .SetValidator(mappedNetworkDriveValidator) .SetValidator(startupFolderValidator) .SetValidator(pathExistsValidator) + .SetValidator(systemFolderValidator) .SetValidator(folderWritableValidator); } @@ -60,4 +62,4 @@ namespace NzbDrone.Api.RootFolders _rootFolderService.Remove(id); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/RootFolders/RootFolderResource.cs b/src/NzbDrone.Api/RootFolders/RootFolderResource.cs index dd13e8495..4c19a23fa 100644 --- a/src/NzbDrone.Api/RootFolders/RootFolderResource.cs +++ b/src/NzbDrone.Api/RootFolders/RootFolderResource.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.RootFolders; namespace NzbDrone.Api.RootFolders diff --git a/src/NzbDrone.Api/Series/SeriesModule.cs b/src/NzbDrone.Api/Series/SeriesModule.cs deleted file mode 100644 index f4fe44135..000000000 --- a/src/NzbDrone.Api/Series/SeriesModule.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using NzbDrone.SignalR; - -namespace NzbDrone.Api.Series -{ - [Obsolete("SeriesModule is Obsolete, Remove with new UI")] - public class SeriesModule : NzbDroneRestModuleWithSignalR - - { - public SeriesModule(IBroadcastSignalRMessage signalRBroadcaster - ) - : base(signalRBroadcaster) - { - GetResourceAll = AllSeries; - GetResourceById = GetSeries; - CreateResource = AddSeries; - UpdateResource = UpdateSeries; - DeleteResource = DeleteSeries; - } - - private SeriesResource GetSeries(int id) - { - return new SeriesResource(); - } - - private List AllSeries() - { - return new List(); - } - - private int AddSeries(SeriesResource seriesResource) - { - return 0; - } - - private void UpdateSeries(SeriesResource seriesResource) - { - throw new NotImplementedException(); - } - - private void DeleteSeries(int id) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/NzbDrone.Api/Series/SeriesResource.cs b/src/NzbDrone.Api/Series/SeriesResource.cs deleted file mode 100644 index 068da9dc6..000000000 --- a/src/NzbDrone.Api/Series/SeriesResource.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using NzbDrone.Api.REST; - -namespace NzbDrone.Api.Series -{ - [Obsolete("SeriesResource is Obsolete, Remove with new UI")] - public class SeriesResource : RestResource - { - public SeriesResource() - { - Title = "Series Endpoint Obsolete"; - } - - //View Only - public string Title { get; set; } - } - -} diff --git a/src/NzbDrone.Api/System/Backup/BackupModule.cs b/src/NzbDrone.Api/System/Backup/BackupModule.cs index 8874ad420..9501da870 100644 --- a/src/NzbDrone.Api/System/Backup/BackupModule.cs +++ b/src/NzbDrone.Api/System/Backup/BackupModule.cs @@ -1,11 +1,12 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; using NzbDrone.Core.Backup; +using Radarr.Http; namespace NzbDrone.Api.System.Backup { - public class BackupModule : NzbDroneRestModule + public class BackupModule : RadarrRestModule { private readonly IBackupService _backupService; diff --git a/src/NzbDrone.Api/System/Backup/BackupResource.cs b/src/NzbDrone.Api/System/Backup/BackupResource.cs index 7eac82838..f94ca56e8 100644 --- a/src/NzbDrone.Api/System/Backup/BackupResource.cs +++ b/src/NzbDrone.Api/System/Backup/BackupResource.cs @@ -1,5 +1,5 @@ -using System; -using NzbDrone.Api.REST; +using System; +using Radarr.Http.REST; using NzbDrone.Core.Backup; namespace NzbDrone.Api.System.Backup diff --git a/src/NzbDrone.Api/System/SystemModule.cs b/src/NzbDrone.Api/System/SystemModule.cs index fc1f27238..cb364abb0 100644 --- a/src/NzbDrone.Api/System/SystemModule.cs +++ b/src/NzbDrone.Api/System/SystemModule.cs @@ -1,6 +1,6 @@ using Nancy; using Nancy.Routing; -using NzbDrone.Api.Extensions; +using Radarr.Http.Extensions; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; using NzbDrone.Core.Configuration; diff --git a/src/NzbDrone.Api/System/Tasks/TaskModule.cs b/src/NzbDrone.Api/System/Tasks/TaskModule.cs index a535b8a2b..4b9667e89 100644 --- a/src/NzbDrone.Api/System/Tasks/TaskModule.cs +++ b/src/NzbDrone.Api/System/Tasks/TaskModule.cs @@ -5,10 +5,11 @@ using NzbDrone.Core.Datastore.Events; using NzbDrone.Core.Jobs; using NzbDrone.Core.Messaging.Events; using NzbDrone.SignalR; +using Radarr.Http; namespace NzbDrone.Api.System.Tasks { - public class TaskModule : NzbDroneRestModuleWithSignalR, IHandle + public class TaskModule : RadarrRestModuleWithSignalR, IHandle { private readonly ITaskManager _taskManager; diff --git a/src/NzbDrone.Api/System/Tasks/TaskResource.cs b/src/NzbDrone.Api/System/Tasks/TaskResource.cs index d4b583aa5..0b47b6cf3 100644 --- a/src/NzbDrone.Api/System/Tasks/TaskResource.cs +++ b/src/NzbDrone.Api/System/Tasks/TaskResource.cs @@ -1,5 +1,5 @@ -using System; -using NzbDrone.Api.REST; +using System; +using Radarr.Http.REST; namespace NzbDrone.Api.System.Tasks { diff --git a/src/NzbDrone.Api/Tags/TagModule.cs b/src/NzbDrone.Api/Tags/TagModule.cs index d2a01667c..741e583a9 100644 --- a/src/NzbDrone.Api/Tags/TagModule.cs +++ b/src/NzbDrone.Api/Tags/TagModule.cs @@ -1,12 +1,13 @@ -using System.Collections.Generic; +using System.Collections.Generic; using NzbDrone.Core.Datastore.Events; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Tags; using NzbDrone.SignalR; +using Radarr.Http; namespace NzbDrone.Api.Tags { - public class TagModule : NzbDroneRestModuleWithSignalR, IHandle + public class TagModule : RadarrRestModuleWithSignalR, IHandle { private readonly ITagService _tagService; diff --git a/src/NzbDrone.Api/Tags/TagResource.cs b/src/NzbDrone.Api/Tags/TagResource.cs index 678107bf5..c22b0e38a 100644 --- a/src/NzbDrone.Api/Tags/TagResource.cs +++ b/src/NzbDrone.Api/Tags/TagResource.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Tags; namespace NzbDrone.Api.Tags diff --git a/src/NzbDrone.Api/Update/UpdateModule.cs b/src/NzbDrone.Api/Update/UpdateModule.cs index 2104f23ea..77ab20af8 100644 --- a/src/NzbDrone.Api/Update/UpdateModule.cs +++ b/src/NzbDrone.Api/Update/UpdateModule.cs @@ -1,11 +1,12 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Core.Update; +using Radarr.Http; namespace NzbDrone.Api.Update { - public class UpdateModule : NzbDroneRestModule + public class UpdateModule : RadarrRestModule { private readonly IRecentUpdateProvider _recentUpdateProvider; @@ -42,4 +43,4 @@ namespace NzbDrone.Api.Update return resources; } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Update/UpdateResource.cs b/src/NzbDrone.Api/Update/UpdateResource.cs index dca6f6725..f07dd1853 100644 --- a/src/NzbDrone.Api/Update/UpdateResource.cs +++ b/src/NzbDrone.Api/Update/UpdateResource.cs @@ -1,8 +1,8 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; -using NzbDrone.Api.REST; +using Radarr.Http.REST; using NzbDrone.Core.Update; namespace NzbDrone.Api.Update diff --git a/src/NzbDrone.Api/Wanted/MovieCutoffModule.cs b/src/NzbDrone.Api/Wanted/MovieCutoffModule.cs index f032f0b12..1fc401ed7 100644 --- a/src/NzbDrone.Api/Wanted/MovieCutoffModule.cs +++ b/src/NzbDrone.Api/Wanted/MovieCutoffModule.cs @@ -1,8 +1,10 @@ +using System.Linq; using NzbDrone.Api.Movies; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Movies; using NzbDrone.Core.Datastore; using NzbDrone.SignalR; +using Radarr.Http; namespace NzbDrone.Api.Wanted { @@ -22,9 +24,18 @@ namespace NzbDrone.Api.Wanted private PagingResource GetCutoffUnmetMovies(PagingResource pagingResource) { - var pagingSpec = pagingResource.MapToPagingSpec("title", SortDirection.Ascending); + var pagingSpec = pagingResource.MapToPagingSpec("title", SortDirection.Ascending); - pagingSpec.FilterExpression = _movieService.ConstructFilterExpression(pagingResource.FilterKey, pagingResource.FilterValue); + var filter = pagingResource.Filters.FirstOrDefault(f => f.Key == "monitored"); + + if (filter != null && filter.Value == "false") + { + pagingSpec.FilterExpressions.Add(v => v.Monitored == false); + } + else + { + pagingSpec.FilterExpressions.Add(v => v.Monitored == true); + } var resource = ApplyToPage(_movieCutoffService.MoviesWhereCutoffUnmet, pagingSpec, v => MapToResource(v, true)); diff --git a/src/NzbDrone.Api/Wanted/MovieMissingModule.cs b/src/NzbDrone.Api/Wanted/MovieMissingModule.cs index e4b1868b2..3b3662253 100644 --- a/src/NzbDrone.Api/Wanted/MovieMissingModule.cs +++ b/src/NzbDrone.Api/Wanted/MovieMissingModule.cs @@ -1,35 +1,36 @@ +using System.Linq; using NzbDrone.Api.Movies; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Movies; using NzbDrone.Core.Datastore; using NzbDrone.SignalR; -using NzbDrone.Core.Download; -using NzbDrone.Core.MediaFiles.Events; -using NzbDrone.Core.Messaging.Events; -using System; -using NzbDrone.Core.Datastore.Events; +using Radarr.Http; namespace NzbDrone.Api.Wanted { class MovieMissingModule : MovieModuleWithSignalR { - protected readonly IMovieService _movieService; - public MovieMissingModule(IMovieService movieService, IQualityUpgradableSpecification qualityUpgradableSpecification, IBroadcastSignalRMessage signalRBroadcaster) : base(movieService, qualityUpgradableSpecification, signalRBroadcaster, "wanted/missing") { - - _movieService = movieService; GetResourcePaged = GetMissingMovies; } private PagingResource GetMissingMovies(PagingResource pagingResource) { - var pagingSpec = pagingResource.MapToPagingSpec("title", SortDirection.Descending); + var pagingSpec = pagingResource.MapToPagingSpec("title", SortDirection.Descending); + var monitoredFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "monitored"); - pagingSpec.FilterExpression = _movieService.ConstructFilterExpression(pagingResource.FilterKey, pagingResource.FilterValue); + if (monitoredFilter != null && monitoredFilter.Value == "false") + { + pagingSpec.FilterExpressions.Add(v => v.Monitored == false); + } + else + { + pagingSpec.FilterExpressions.Add(v => v.Monitored == true); + } var resource = ApplyToPage(_movieService.MoviesWithoutFiles, pagingSpec, v => MapToResource(v, true)); diff --git a/src/NzbDrone.App.Test/NzbDrone.Host.Test.csproj b/src/NzbDrone.App.Test/NzbDrone.Host.Test.csproj index 6a3fa50e5..ecb4465f6 100644 --- a/src/NzbDrone.App.Test/NzbDrone.Host.Test.csproj +++ b/src/NzbDrone.App.Test/NzbDrone.Host.Test.csproj @@ -9,7 +9,7 @@ Library Properties NzbDrone.App.Test - NzbDrone.App.Test + Radarr.App.Test v4.6.1 512 ..\ @@ -116,12 +116,12 @@ - xcopy /s /y "$(SolutionDir)\..\_output\NzbDrone.Mono.*" "$(TargetDir)" - xcopy /s /y "$(SolutionDir)\..\_output\NzbDrone.Windows.*" "$(TargetDir)" + xcopy /s /y "$(SolutionDir)\..\_output\Radarr.Mono.*" "$(TargetDir)" + xcopy /s /y "$(SolutionDir)\..\_output\Radarr.Windows.*" "$(TargetDir)" - cp -rv $(SolutionDir)\..\_output\NzbDrone.Mono.* $(TargetDir) - cp -rv $(SolutionDir)\..\_output\NzbDrone.Windows.* $(TargetDir) + cp -rv $(SolutionDir)\..\_output\Radarr.Mono.* $(TargetDir) + cp -rv $(SolutionDir)\..\_output\Radarr.Windows.* $(TargetDir) - + \ No newline at end of file diff --git a/src/NzbDrone.Core/Profiles/Delay/DelayProfileService.cs b/src/NzbDrone.Core/Profiles/Delay/DelayProfileService.cs index a367ce4eb..7f9a1159d 100644 --- a/src/NzbDrone.Core/Profiles/Delay/DelayProfileService.cs +++ b/src/NzbDrone.Core/Profiles/Delay/DelayProfileService.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using NzbDrone.Common.Extensions; @@ -11,6 +11,7 @@ namespace NzbDrone.Core.Profiles.Delay void Delete(int id); List All(); DelayProfile Get(int id); + List AllForTag(int tagId); List AllForTags(HashSet tagIds); DelayProfile BestForTags(HashSet tagIds); } @@ -60,6 +61,12 @@ namespace NzbDrone.Core.Profiles.Delay return _repo.Get(id); } + public List AllForTag(int tagId) + { + return All().Where(r => r.Tags.Contains(tagId)) + .ToList(); + } + public List AllForTags(HashSet tagIds) { return _repo.All().Where(r => r.Tags.Intersect(tagIds).Any() || r.Tags.Empty()).ToList(); diff --git a/src/NzbDrone.Core/Properties/AssemblyInfo.cs b/src/NzbDrone.Core/Properties/AssemblyInfo.cs index 7ddb4d5ec..dfe681ea4 100644 --- a/src/NzbDrone.Core/Properties/AssemblyInfo.cs +++ b/src/NzbDrone.Core/Properties/AssemblyInfo.cs @@ -6,9 +6,9 @@ using System.Runtime.InteropServices; // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("NzbDrone.Core")] +[assembly: AssemblyTitle("Radarr.Core")] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("3C29FEF7-4B07-49ED-822E-1C29DC49BFAB")] -[assembly: InternalsVisibleTo("NzbDrone.Core.Test")] +[assembly: InternalsVisibleTo("Radarr.Core.Test")] diff --git a/src/NzbDrone.Core/Queue/EstimatedCompletionTimeComparer.cs b/src/NzbDrone.Core/Queue/EstimatedCompletionTimeComparer.cs new file mode 100644 index 000000000..e8c52e1ab --- /dev/null +++ b/src/NzbDrone.Core/Queue/EstimatedCompletionTimeComparer.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; + +namespace NzbDrone.Core.Queue +{ + public class EstimatedCompletionTimeComparer : IComparer + { + public int Compare(DateTime? x, DateTime? y) + { + if (!x.HasValue && !y.HasValue) + { + return 0; + } + + if (!x.HasValue && y.HasValue) + { + return 1; + } + + if (x.HasValue && !y.HasValue) + { + return -1; + } + + if (x.Value > y.Value) + { + return 1; + } + + if (x.Value < y.Value) + { + return -1; + } + + return 0; + } + } +} diff --git a/src/NzbDrone.Core/Queue/Queue.cs b/src/NzbDrone.Core/Queue/Queue.cs index 6a2b2b0bd..3f033d9e2 100644 --- a/src/NzbDrone.Core/Queue/Queue.cs +++ b/src/NzbDrone.Core/Queue/Queue.cs @@ -24,5 +24,8 @@ namespace NzbDrone.Core.Queue public string DownloadId { get; set; } public RemoteMovie RemoteMovie { get; set; } public DownloadProtocol Protocol { get; set; } + public string DownloadClient { get; set; } + public string Indexer { get; set; } + public string ErrorMessage { get; set; } } } diff --git a/src/NzbDrone.Core/Queue/QueueService.cs b/src/NzbDrone.Core/Queue/QueueService.cs index 76bfbab07..71b363697 100644 --- a/src/NzbDrone.Core/Queue/QueueService.cs +++ b/src/NzbDrone.Core/Queue/QueueService.cs @@ -66,7 +66,10 @@ namespace NzbDrone.Core.Queue RemoteMovie = trackedDownload.RemoteMovie, DownloadId = trackedDownload.DownloadItem.DownloadId, Protocol = trackedDownload.Protocol, - Movie = movie + Movie = movie, + DownloadClient = trackedDownload.DownloadItem.DownloadClient, + Indexer = trackedDownload.Indexer + }; if (queue.Timeleft.HasValue) diff --git a/src/NzbDrone.Core/Queue/TimeleftComparer.cs b/src/NzbDrone.Core/Queue/TimeleftComparer.cs new file mode 100644 index 000000000..2c051deeb --- /dev/null +++ b/src/NzbDrone.Core/Queue/TimeleftComparer.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; + +namespace NzbDrone.Core.Queue +{ + public class TimeleftComparer : IComparer + { + public int Compare(TimeSpan? x, TimeSpan? y) + { + if (!x.HasValue && !y.HasValue) + { + return 0; + } + + if (!x.HasValue && y.HasValue) + { + return 1; + } + + if (x.HasValue && !y.HasValue) + { + return -1; + } + + if (x.Value > y.Value) + { + return 1; + } + + if (x.Value < y.Value) + { + return -1; + } + + return 0; + } + } +} diff --git a/src/NzbDrone.Core/NzbDrone.Core.dll.config b/src/NzbDrone.Core/Radarr.Core.dll.config similarity index 100% rename from src/NzbDrone.Core/NzbDrone.Core.dll.config rename to src/NzbDrone.Core/Radarr.Core.dll.config diff --git a/src/NzbDrone.Core/Restrictions/RestrictionService.cs b/src/NzbDrone.Core/Restrictions/RestrictionService.cs index 5d7cfba8d..561add650 100644 --- a/src/NzbDrone.Core/Restrictions/RestrictionService.cs +++ b/src/NzbDrone.Core/Restrictions/RestrictionService.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using NLog; using NzbDrone.Common.Extensions; @@ -34,7 +34,7 @@ namespace NzbDrone.Core.Restrictions public List AllForTag(int tagId) { - return _repo.All().Where(r => r.Tags.Contains(tagId) || r.Tags.Empty()).ToList(); + return _repo.All().Where(r => r.Tags.Contains(tagId)).ToList(); } public List AllForTags(HashSet tagIds) diff --git a/src/NzbDrone.Core/RootFolders/RootFolderService.cs b/src/NzbDrone.Core/RootFolders/RootFolderService.cs index 437e102a7..b72cb472b 100644 --- a/src/NzbDrone.Core/RootFolders/RootFolderService.cs +++ b/src/NzbDrone.Core/RootFolders/RootFolderService.cs @@ -134,11 +134,6 @@ namespace NzbDrone.Core.RootFolders throw new InvalidOperationException("Recent directory already exists."); } - if (_configService.DownloadedMoviesFolder.IsNotNullOrWhiteSpace() && _configService.DownloadedMoviesFolder.PathEquals(rootFolder.Path)) - { - throw new InvalidOperationException("Drone Factory folder cannot be used."); - } - if (!_diskProvider.FolderWritable(rootFolder.Path)) { throw new UnauthorizedAccessException(string.Format("Root folder path '{0}' is not writable by user '{1}'", rootFolder.Path, Environment.UserName)); diff --git a/src/NzbDrone.Core/Tags/TagDetails.cs b/src/NzbDrone.Core/Tags/TagDetails.cs new file mode 100644 index 000000000..8d134622a --- /dev/null +++ b/src/NzbDrone.Core/Tags/TagDetails.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using NzbDrone.Core.Datastore; + +namespace NzbDrone.Core.Tags +{ + public class TagDetails : ModelBase + { + public string Label { get; set; } + public List MovieIds { get; set; } + public List NotificationIds { get; set; } + public List RestrictionIds { get; set; } + public List DelayProfileIds { get; set; } + } +} diff --git a/src/NzbDrone.Core/Tags/TagService.cs b/src/NzbDrone.Core/Tags/TagService.cs index b7637a6f8..651a17ad6 100644 --- a/src/NzbDrone.Core/Tags/TagService.cs +++ b/src/NzbDrone.Core/Tags/TagService.cs @@ -1,6 +1,10 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Notifications; +using NzbDrone.Core.Profiles.Delay; +using NzbDrone.Core.Restrictions; +using NzbDrone.Core.Movies; namespace NzbDrone.Core.Tags { @@ -8,6 +12,9 @@ namespace NzbDrone.Core.Tags { Tag GetTag(int tagId); Tag GetTag(string tag); + List GetTags(IEnumerable ids); + TagDetails Details(int tagId); + List Details(); List All(); Tag Add(Tag tag); Tag Update(Tag tag); @@ -18,11 +25,24 @@ namespace NzbDrone.Core.Tags { private readonly ITagRepository _repo; private readonly IEventAggregator _eventAggregator; + private readonly IDelayProfileService _delayProfileService; + private readonly INotificationFactory _notificationFactory; + private readonly IRestrictionService _restrictionService; + private readonly IMovieService _movieService; - public TagService(ITagRepository repo, IEventAggregator eventAggregator) + public TagService(ITagRepository repo, + IEventAggregator eventAggregator, + IDelayProfileService delayProfileService, + INotificationFactory notificationFactory, + IRestrictionService restrictionService, + IMovieService movieService) { _repo = repo; _eventAggregator = eventAggregator; + _delayProfileService = delayProfileService; + _notificationFactory = notificationFactory; + _restrictionService = restrictionService; + _movieService = movieService; } public Tag GetTag(int tagId) @@ -42,6 +62,57 @@ namespace NzbDrone.Core.Tags } } + public List GetTags(IEnumerable ids) + { + return _repo.Get(ids).ToList(); + } + + public TagDetails Details(int tagId) + { + var tag = GetTag(tagId); + var delayProfiles = _delayProfileService.AllForTag(tagId); + var notifications = _notificationFactory.AllForTag(tagId); + var restrictions = _restrictionService.AllForTag(tagId); + var movies = _movieService.AllForTag(tagId); + + return new TagDetails + { + Id = tagId, + Label = tag.Label, + DelayProfileIds = delayProfiles.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() + }; + } + + public List Details() + { + var tags = All(); + var delayProfiles = _delayProfileService.All(); + var notifications = _notificationFactory.All(); + var restrictions = _restrictionService.All(); + var movies = _movieService.GetAllMovies(); + + var details = new List(); + + foreach (var tag in tags) + { + details.Add(new TagDetails + { + Id = tag.Id, + Label = tag.Label, + DelayProfileIds = delayProfiles.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() + } + ); + } + + return details; + } + public List All() { return _repo.All().OrderBy(t => t.Label).ToList(); diff --git a/src/NzbDrone.Core/ThingiProvider/IProviderFactory.cs b/src/NzbDrone.Core/ThingiProvider/IProviderFactory.cs index ce6519e1b..bc52f9e16 100644 --- a/src/NzbDrone.Core/ThingiProvider/IProviderFactory.cs +++ b/src/NzbDrone.Core/ThingiProvider/IProviderFactory.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using FluentValidation.Results; namespace NzbDrone.Core.ThingiProvider @@ -20,5 +20,6 @@ namespace NzbDrone.Core.ThingiProvider TProvider GetInstance(TProviderDefinition definition); ValidationResult Test(TProviderDefinition definition); object RequestAction(TProviderDefinition definition, string action, IDictionary query); + List AllForTag(int tagId); } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Core/ThingiProvider/ProviderDefinition.cs b/src/NzbDrone.Core/ThingiProvider/ProviderDefinition.cs index 45bd5a25a..388bf362f 100644 --- a/src/NzbDrone.Core/ThingiProvider/ProviderDefinition.cs +++ b/src/NzbDrone.Core/ThingiProvider/ProviderDefinition.cs @@ -1,9 +1,15 @@ -using NzbDrone.Core.Datastore; +using System.Collections.Generic; +using NzbDrone.Core.Datastore; namespace NzbDrone.Core.ThingiProvider { public abstract class ProviderDefinition : ModelBase { + protected ProviderDefinition() + { + Tags = new HashSet(); + } + private IProviderConfig _settings; public string Name { get; set; } @@ -12,6 +18,7 @@ namespace NzbDrone.Core.ThingiProvider public string ConfigContract { get; set; } public virtual bool Enable { get; set; } public ProviderMessage Message { get; set; } + public HashSet Tags { get; set; } public IProviderConfig Settings { diff --git a/src/NzbDrone.Core/ThingiProvider/ProviderFactory.cs b/src/NzbDrone.Core/ThingiProvider/ProviderFactory.cs index 70929efe4..d948ec9eb 100644 --- a/src/NzbDrone.Core/ThingiProvider/ProviderFactory.cs +++ b/src/NzbDrone.Core/ThingiProvider/ProviderFactory.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using FluentValidation.Results; @@ -167,5 +167,11 @@ namespace NzbDrone.Core.ThingiProvider _providerRepository.Delete(invalidDefinition); } } + + public List AllForTag(int tagId) + { + return All().Where(p => p.Tags.Contains(tagId)) + .ToList(); + } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Core/Update/Commands/ApplicationUpdateCommand.cs b/src/NzbDrone.Core/Update/Commands/ApplicationUpdateCommand.cs index 8656ffef8..710d8d6d4 100644 --- a/src/NzbDrone.Core/Update/Commands/ApplicationUpdateCommand.cs +++ b/src/NzbDrone.Core/Update/Commands/ApplicationUpdateCommand.cs @@ -1,10 +1,11 @@ -using NzbDrone.Core.Messaging.Commands; +using NzbDrone.Core.Messaging.Commands; namespace NzbDrone.Core.Update.Commands { public class ApplicationUpdateCommand : Command { public override bool SendUpdatesToClient => true; + public override bool RequiresDiskAccess => true; public override string CompletionMessage => "Restarting Radarr to apply updates"; } diff --git a/src/NzbDrone.Core/Update/InstallUpdateService.cs b/src/NzbDrone.Core/Update/InstallUpdateService.cs index e42a075cd..42970ba19 100644 --- a/src/NzbDrone.Core/Update/InstallUpdateService.cs +++ b/src/NzbDrone.Core/Update/InstallUpdateService.cs @@ -167,7 +167,7 @@ namespace NzbDrone.Core.Update throw new UpdateFailedException("Update Script: '{0}' does not exist", scriptPath); } - _logger.Info("Removing NzbDrone.Update"); + _logger.Info("Removing Radarr.Update"); _diskProvider.DeleteFolder(_appFolderInfo.GetUpdateClientFolder(), true); _logger.ProgressInfo("Starting update script: {0}", _configFileProvider.UpdateScriptPath); diff --git a/src/NzbDrone.Core/Validation/Paths/DroneFactoryValidator.cs b/src/NzbDrone.Core/Validation/Paths/DroneFactoryValidator.cs deleted file mode 100644 index 63ed8db77..000000000 --- a/src/NzbDrone.Core/Validation/Paths/DroneFactoryValidator.cs +++ /dev/null @@ -1,28 +0,0 @@ -using FluentValidation.Validators; -using NzbDrone.Common.Extensions; -using NzbDrone.Core.Configuration; - -namespace NzbDrone.Core.Validation.Paths -{ - public class DroneFactoryValidator : PropertyValidator - { - private readonly IConfigService _configService; - - public DroneFactoryValidator(IConfigService configService) - : base("Path is already used for drone factory") - { - _configService = configService; - } - - protected override bool IsValid(PropertyValidatorContext context) - { - if (context.PropertyValue == null) return false; - - var droneFactory = _configService.DownloadedMoviesFolder; - - if (string.IsNullOrWhiteSpace(droneFactory)) return true; - - return !droneFactory.PathEquals(context.PropertyValue.ToString()); - } - } -} \ No newline at end of file diff --git a/src/NzbDrone.Core/Validation/Paths/MovieAncestorValidator.cs b/src/NzbDrone.Core/Validation/Paths/MovieAncestorValidator.cs index e72af6221..91df0ffa3 100644 --- a/src/NzbDrone.Core/Validation/Paths/MovieAncestorValidator.cs +++ b/src/NzbDrone.Core/Validation/Paths/MovieAncestorValidator.cs @@ -10,7 +10,7 @@ namespace NzbDrone.Core.Validation.Paths private readonly IMovieService _movieService; public MovieAncestorValidator(IMovieService movieService) - : base("Path is an ancestor of an existing path") + : base("Path is an ancestor of an existing movie") { _movieService = movieService; } diff --git a/src/NzbDrone.Core/Validation/Paths/SystemFolderValidator.cs b/src/NzbDrone.Core/Validation/Paths/SystemFolderValidator.cs new file mode 100644 index 000000000..ad321f87a --- /dev/null +++ b/src/NzbDrone.Core/Validation/Paths/SystemFolderValidator.cs @@ -0,0 +1,91 @@ +using System; +using FluentValidation.Validators; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Extensions; + +namespace NzbDrone.Core.Validation.Paths +{ + public class SystemFolderValidator : PropertyValidator + { + public SystemFolderValidator() + : base("Is {relationship} system folder {systemFolder}") + { + } + + protected override bool IsValid(PropertyValidatorContext context) + { + var folder = context.PropertyValue.ToString(); + + if (OsInfo.IsWindows) + { + var windowsFolder = Environment.GetFolderPath(Environment.SpecialFolder.Windows); + context.MessageFormatter.AppendArgument("systemFolder", windowsFolder); + + if (windowsFolder.PathEquals(folder)) + { + context.MessageFormatter.AppendArgument("relationship", "set to"); + + return false; + } + + if (windowsFolder.IsParentPath(folder)) + { + context.MessageFormatter.AppendArgument("relationship", "child of"); + + return false; + } + } + else if (OsInfo.IsOsx) + { + var systemFolder = "/System"; + context.MessageFormatter.AppendArgument("systemFolder", systemFolder); + + if (systemFolder.PathEquals(folder)) + { + context.MessageFormatter.AppendArgument("relationship", "child of"); + + return false; + } + + if (systemFolder.IsParentPath(folder)) + { + context.MessageFormatter.AppendArgument("relationship", "child of"); + + return false; + } + } + else + { + var folders = new[] + { + "/bin", + "/boot", + "/lib", + "/sbin", + "/proc" + }; + + foreach (var f in folders) + { + context.MessageFormatter.AppendArgument("systemFolder", f); + + if (f.PathEquals(folder)) + { + context.MessageFormatter.AppendArgument("relationship", "child of"); + + return false; + } + + if (f.IsParentPath(folder)) + { + context.MessageFormatter.AppendArgument("relationship", "child of"); + + return false; + } + } + } + + return true; + } + } +} diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index 9f7c08b54..7d4c992f9 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -4,9 +4,11 @@ using System.Threading; using NLog; using NzbDrone.Common.Composition; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Exceptions; using NzbDrone.Common.Instrumentation; using NzbDrone.Common.Processes; using NzbDrone.Common.Security; +using NzbDrone.Core.Configuration; using NzbDrone.Core.Instrumentation; namespace Radarr.Host @@ -49,6 +51,10 @@ namespace Radarr.Host SpinToExit(appMode); } } + catch (InvalidConfigFileException ex) + { + throw new RadarrStartupException(ex); + } catch (TerminateApplicationException e) { Logger.Info(e.Message); diff --git a/src/NzbDrone.Host/MainAppContainerBuilder.cs b/src/NzbDrone.Host/MainAppContainerBuilder.cs index e14560c38..3bbc0cc52 100644 --- a/src/NzbDrone.Host/MainAppContainerBuilder.cs +++ b/src/NzbDrone.Host/MainAppContainerBuilder.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using Nancy.Bootstrapper; -using NzbDrone.Api; +using Radarr.Http; using NzbDrone.Common.Composition; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Http.Dispatchers; @@ -15,9 +15,11 @@ namespace Radarr.Host var assemblies = new List { "Radarr.Host", - "NzbDrone.Core", - "NzbDrone.Api", - "NzbDrone.SignalR" + "Radarr.Core", + "Radarr.Api", + "Radarr.SignalR", + "Radarr.Api.V2", + "Radarr.Http" }; return new MainAppContainerBuilder(args, assemblies).Container; @@ -28,7 +30,7 @@ namespace Radarr.Host { AutoRegisterImplementations(); - Container.Register(); + Container.Register(); Container.Register(); } } diff --git a/src/NzbDrone.Host/NzbDrone.Host.csproj b/src/NzbDrone.Host/NzbDrone.Host.csproj index dfd0f6f2f..1933f80c6 100644 --- a/src/NzbDrone.Host/NzbDrone.Host.csproj +++ b/src/NzbDrone.Host/NzbDrone.Host.csproj @@ -197,6 +197,14 @@ {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36} NzbDrone.SignalR + + {38497dc6-e488-4b9e-a973-a1a7961b33c4} + Radarr.Api.V2 + + + {c5953dab-89db-46d9-a401-d620f54b776e} + Radarr.Http + diff --git a/src/NzbDrone.Host/Owin/MiddleWare/SignalRMiddleWare.cs b/src/NzbDrone.Host/Owin/MiddleWare/SignalRMiddleWare.cs index 008919803..51ac8bfbe 100644 --- a/src/NzbDrone.Host/Owin/MiddleWare/SignalRMiddleWare.cs +++ b/src/NzbDrone.Host/Owin/MiddleWare/SignalRMiddleWare.cs @@ -15,12 +15,14 @@ namespace Radarr.Host.Owin.MiddleWare SignalRDependencyResolver.Register(container); SignalRJsonSerializer.Register(); + // Half the default time (110s) to get under nginx's default 60 proxy_read_timeout + GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(55); GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromMinutes(3); } public void Attach(IAppBuilder appBuilder) { - appBuilder.MapConnection("/signalr", typeof(NzbDronePersistentConnection), new ConnectionConfiguration()); + appBuilder.MapSignalR("/signalr", typeof(NzbDronePersistentConnection), new ConnectionConfiguration()); } } } diff --git a/src/NzbDrone.Host/Router.cs b/src/NzbDrone.Host/Router.cs index cfc925929..17f1e33c3 100644 --- a/src/NzbDrone.Host/Router.cs +++ b/src/NzbDrone.Host/Router.cs @@ -44,27 +44,27 @@ namespace Radarr.Host case ApplicationModes.InstallService: { _logger.Debug("Install Service selected"); - if (_serviceProvider.ServiceExist(ServiceProvider.NZBDRONE_SERVICE_NAME)) + if (_serviceProvider.ServiceExist(ServiceProvider.SERVICE_NAME)) { _consoleService.PrintServiceAlreadyExist(); } else { - _serviceProvider.Install(ServiceProvider.NZBDRONE_SERVICE_NAME); - _serviceProvider.Start(ServiceProvider.NZBDRONE_SERVICE_NAME); + _serviceProvider.Install(ServiceProvider.SERVICE_NAME); + _serviceProvider.Start(ServiceProvider.SERVICE_NAME); } break; } case ApplicationModes.UninstallService: { _logger.Debug("Uninstall Service selected"); - if (!_serviceProvider.ServiceExist(ServiceProvider.NZBDRONE_SERVICE_NAME)) + if (!_serviceProvider.ServiceExist(ServiceProvider.SERVICE_NAME)) { _consoleService.PrintServiceDoesNotExist(); } else { - _serviceProvider.UnInstall(ServiceProvider.NZBDRONE_SERVICE_NAME); + _serviceProvider.UnInstall(ServiceProvider.SERVICE_NAME); } break; diff --git a/src/NzbDrone.Host/SingleInstancePolicy.cs b/src/NzbDrone.Host/SingleInstancePolicy.cs index 1978c50e6..dd2f74190 100644 --- a/src/NzbDrone.Host/SingleInstancePolicy.cs +++ b/src/NzbDrone.Host/SingleInstancePolicy.cs @@ -65,8 +65,8 @@ namespace Radarr.Host { var currentId = _processProvider.GetCurrentProcess().Id; - var otherProcesses = _processProvider.FindProcessByName(ProcessProvider.NZB_DRONE_CONSOLE_PROCESS_NAME) - .Union(_processProvider.FindProcessByName(ProcessProvider.NZB_DRONE_PROCESS_NAME)) + var otherProcesses = _processProvider.FindProcessByName(ProcessProvider.RADARR_CONSOLE_PROCESS_NAME) + .Union(_processProvider.FindProcessByName(ProcessProvider.RADARR_PROCESS_NAME)) .Select(c => c.Id) .Except(new[] { currentId }) .ToList(); diff --git a/src/NzbDrone.Integration.Test/Client/ClientBase.cs b/src/NzbDrone.Integration.Test/Client/ClientBase.cs index 884fe992a..5ea21256c 100644 --- a/src/NzbDrone.Integration.Test/Client/ClientBase.cs +++ b/src/NzbDrone.Integration.Test/Client/ClientBase.cs @@ -1,9 +1,10 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Net; using FluentAssertions; using NLog; using NzbDrone.Api; -using NzbDrone.Api.REST; +using Radarr.Http.REST; +using Radarr.Http; using NzbDrone.Common.Serializer; using RestSharp; using System.Linq; @@ -176,4 +177,4 @@ namespace NzbDrone.Integration.Test.Client Execute(request, statusCode); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Integration.Test/CorsFixture.cs b/src/NzbDrone.Integration.Test/CorsFixture.cs index e4c5b71e0..2e00e077b 100644 --- a/src/NzbDrone.Integration.Test/CorsFixture.cs +++ b/src/NzbDrone.Integration.Test/CorsFixture.cs @@ -1,6 +1,6 @@ using FluentAssertions; using NUnit.Framework; -using NzbDrone.Api.Extensions; +using Radarr.Http.Extensions; using RestSharp; namespace NzbDrone.Integration.Test diff --git a/src/NzbDrone.Integration.Test/IntegrationTest.cs b/src/NzbDrone.Integration.Test/IntegrationTest.cs index 592d3b55e..0c725dbac 100644 --- a/src/NzbDrone.Integration.Test/IntegrationTest.cs +++ b/src/NzbDrone.Integration.Test/IntegrationTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using NLog; using NzbDrone.Core.Indexers.Newznab; using NzbDrone.Test.Common; +using Radarr.Http.ClientSchema; namespace NzbDrone.Integration.Test { @@ -33,7 +34,7 @@ namespace NzbDrone.Integration.Test Implementation = nameof(Newznab), Name = "NewznabTest", Protocol = Core.Indexers.DownloadProtocol.Usenet, - Fields = Api.ClientSchema.SchemaBuilder.ToSchema(new NewznabSettings()) + Fields = SchemaBuilder.ToSchema(new NewznabSettings()) }); } diff --git a/src/NzbDrone.Integration.Test/NzbDrone.Integration.Test.csproj b/src/NzbDrone.Integration.Test/NzbDrone.Integration.Test.csproj index 6334891af..f96c00d2c 100644 --- a/src/NzbDrone.Integration.Test/NzbDrone.Integration.Test.csproj +++ b/src/NzbDrone.Integration.Test/NzbDrone.Integration.Test.csproj @@ -8,7 +8,7 @@ Library Properties NzbDrone.Integration.Test - NzbDrone.Integration.Test + Radarr.Integration.Test v4.6.1 512 ..\ @@ -162,6 +162,10 @@ {CADDFCE0-7509-4430-8364-2074E1EEFCA2} NzbDrone.Test.Common + + {c5953dab-89db-46d9-a401-d620f54b776e} + Radarr.Http + @@ -175,12 +179,12 @@ - xcopy /s /y "$(SolutionDir)\..\_output\NzbDrone.Mono.*" "$(TargetDir)" - xcopy /s /y "$(SolutionDir)\..\_output\NzbDrone.Windows.*" "$(TargetDir)" + xcopy /s /y "$(SolutionDir)\..\_output\Radarr.Mono.*" "$(TargetDir)" + xcopy /s /y "$(SolutionDir)\..\_output\Radarr.Windows.*" "$(TargetDir)" - cp -rv $(SolutionDir)\..\_output\NzbDrone.Mono.* $(TargetDir) - cp -rv $(SolutionDir)\..\_output\NzbDrone.Windows.* $(TargetDir) + cp -rv $(SolutionDir)\..\_output\Radarr.Mono.* $(TargetDir) + cp -rv $(SolutionDir)\..\_output\Radarr.Windows.* $(TargetDir) + \ No newline at end of file diff --git a/src/Radarr.Api.V2/RadarrV2FeedModule.cs b/src/Radarr.Api.V2/RadarrV2FeedModule.cs new file mode 100644 index 000000000..f71e28cca --- /dev/null +++ b/src/Radarr.Api.V2/RadarrV2FeedModule.cs @@ -0,0 +1,12 @@ +using Nancy; + +namespace Radarr.Api.V2 +{ + public abstract class RadarrV2FeedModule : NancyModule + { + protected RadarrV2FeedModule(string resource) + : base("/feed/v2/" + resource.Trim('/')) + { + } + } +} diff --git a/src/Radarr.Api.V2/RadarrV2Module.cs b/src/Radarr.Api.V2/RadarrV2Module.cs new file mode 100644 index 000000000..6d05e5562 --- /dev/null +++ b/src/Radarr.Api.V2/RadarrV2Module.cs @@ -0,0 +1,12 @@ +using Nancy; + +namespace Radarr.Api.V2 +{ + public abstract class RadarrV2Module : NancyModule + { + protected RadarrV2Module(string resource) + : base("/api/v2/" + resource.Trim('/')) + { + } + } +} diff --git a/src/Radarr.Api.V2/RemotePathMappings/RemotePathMappingModule.cs b/src/Radarr.Api.V2/RemotePathMappings/RemotePathMappingModule.cs new file mode 100644 index 000000000..de7e61d9c --- /dev/null +++ b/src/Radarr.Api.V2/RemotePathMappings/RemotePathMappingModule.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using FluentValidation; +using NzbDrone.Core.RemotePathMappings; +using NzbDrone.Core.Validation.Paths; +using Radarr.Http; + +namespace Radarr.Api.V2.RemotePathMappings +{ + public class RemotePathMappingModule : RadarrRestModule + { + private readonly IRemotePathMappingService _remotePathMappingService; + + public RemotePathMappingModule(IRemotePathMappingService remotePathMappingService, + PathExistsValidator pathExistsValidator, + MappedNetworkDriveValidator mappedNetworkDriveValidator) + { + _remotePathMappingService = remotePathMappingService; + + GetResourceAll = GetMappings; + GetResourceById = GetMappingById; + CreateResource = CreateMapping; + DeleteResource = DeleteMapping; + UpdateResource = UpdateMapping; + + SharedValidator.RuleFor(c => c.Host) + .NotEmpty(); + + // We cannot use IsValidPath here, because it's a remote path, possibly other OS. + SharedValidator.RuleFor(c => c.RemotePath) + .NotEmpty(); + + SharedValidator.RuleFor(c => c.LocalPath) + .Cascade(CascadeMode.StopOnFirstFailure) + .IsValidPath() + .SetValidator(mappedNetworkDriveValidator) + .SetValidator(pathExistsValidator); + } + + private RemotePathMappingResource GetMappingById(int id) + { + return _remotePathMappingService.Get(id).ToResource(); + } + + private int CreateMapping(RemotePathMappingResource resource) + { + var model = resource.ToModel(); + + return _remotePathMappingService.Add(model).Id; + } + + private List GetMappings() + { + return _remotePathMappingService.All().ToResource(); + } + + private void DeleteMapping(int id) + { + _remotePathMappingService.Remove(id); + } + + private void UpdateMapping(RemotePathMappingResource resource) + { + var mapping = resource.ToModel(); + + _remotePathMappingService.Update(mapping); + } + } +} diff --git a/src/Radarr.Api.V2/RemotePathMappings/RemotePathMappingResource.cs b/src/Radarr.Api.V2/RemotePathMappings/RemotePathMappingResource.cs new file mode 100644 index 000000000..ab449fc51 --- /dev/null +++ b/src/Radarr.Api.V2/RemotePathMappings/RemotePathMappingResource.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Core.RemotePathMappings; +using Radarr.Http.REST; + +namespace Radarr.Api.V2.RemotePathMappings +{ + public class RemotePathMappingResource : RestResource + { + public string Host { get; set; } + public string RemotePath { get; set; } + public string LocalPath { get; set; } + } + + public static class RemotePathMappingResourceMapper + { + public static RemotePathMappingResource ToResource(this RemotePathMapping model) + { + if (model == null) return null; + + return new RemotePathMappingResource + { + Id = model.Id, + + Host = model.Host, + RemotePath = model.RemotePath, + LocalPath = model.LocalPath + }; + } + + public static RemotePathMapping ToModel(this RemotePathMappingResource resource) + { + if (resource == null) return null; + + return new RemotePathMapping + { + Id = resource.Id, + + Host = resource.Host, + RemotePath = resource.RemotePath, + LocalPath = resource.LocalPath + }; + } + + public static List ToResource(this IEnumerable models) + { + return models.Select(ToResource).ToList(); + } + } +} diff --git a/src/Radarr.Api.V2/Restrictions/RestrictionModule.cs b/src/Radarr.Api.V2/Restrictions/RestrictionModule.cs new file mode 100644 index 000000000..130802abb --- /dev/null +++ b/src/Radarr.Api.V2/Restrictions/RestrictionModule.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using FluentValidation.Results; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Restrictions; +using Radarr.Http; + +namespace Radarr.Api.V2.Restrictions +{ + public class RestrictionModule : RadarrRestModule + { + private readonly IRestrictionService _restrictionService; + + + public RestrictionModule(IRestrictionService restrictionService) + { + _restrictionService = restrictionService; + + GetResourceById = Get; + GetResourceAll = GetAll; + CreateResource = Create; + UpdateResource = Update; + DeleteResource = Delete; + + SharedValidator.Custom(restriction => + { + if (restriction.Ignored.IsNullOrWhiteSpace() && restriction.Required.IsNullOrWhiteSpace()) + { + return new ValidationFailure("", "Either 'Must contain' or 'Must not contain' is required"); + } + + return null; + }); + } + + private RestrictionResource Get(int id) + { + return _restrictionService.Get(id).ToResource(); + } + + private List GetAll() + { + return _restrictionService.All().ToResource(); + } + + private int Create(RestrictionResource resource) + { + return _restrictionService.Add(resource.ToModel()).Id; + } + + private void Update(RestrictionResource resource) + { + _restrictionService.Update(resource.ToModel()); + } + + private void Delete(int id) + { + _restrictionService.Delete(id); + } + } +} diff --git a/src/Radarr.Api.V2/Restrictions/RestrictionResource.cs b/src/Radarr.Api.V2/Restrictions/RestrictionResource.cs new file mode 100644 index 000000000..c73c569b5 --- /dev/null +++ b/src/Radarr.Api.V2/Restrictions/RestrictionResource.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Core.Restrictions; +using Radarr.Http.REST; + +namespace Radarr.Api.V2.Restrictions +{ + public class RestrictionResource : RestResource + { + public string Required { get; set; } + public string Preferred { get; set; } + public string Ignored { get; set; } + public HashSet Tags { get; set; } + + public RestrictionResource() + { + Tags = new HashSet(); + } + } + + public static class RestrictionResourceMapper + { + public static RestrictionResource ToResource(this Restriction model) + { + if (model == null) return null; + + return new RestrictionResource + { + Id = model.Id, + + Required = model.Required, + Preferred = model.Preferred, + Ignored = model.Ignored, + Tags = new HashSet(model.Tags) + }; + } + + public static Restriction ToModel(this RestrictionResource resource) + { + if (resource == null) return null; + + return new Restriction + { + Id = resource.Id, + + Required = resource.Required, + Preferred = resource.Preferred, + Ignored = resource.Ignored, + Tags = new HashSet(resource.Tags) + }; + } + + public static List ToResource(this IEnumerable models) + { + return models.Select(ToResource).ToList(); + } + } +} diff --git a/src/Radarr.Api.V2/RootFolders/RootFolderModule.cs b/src/Radarr.Api.V2/RootFolders/RootFolderModule.cs new file mode 100644 index 000000000..cf79303c6 --- /dev/null +++ b/src/Radarr.Api.V2/RootFolders/RootFolderModule.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; +using FluentValidation; +using NzbDrone.Core.RootFolders; +using NzbDrone.Core.Validation.Paths; +using NzbDrone.SignalR; +using Radarr.Http; + +namespace Radarr.Api.V2.RootFolders +{ + public class RootFolderModule : RadarrRestModuleWithSignalR + { + private readonly IRootFolderService _rootFolderService; + + public RootFolderModule(IRootFolderService rootFolderService, + IBroadcastSignalRMessage signalRBroadcaster, + RootFolderValidator rootFolderValidator, + PathExistsValidator pathExistsValidator, + MappedNetworkDriveValidator mappedNetworkDriveValidator, + StartupFolderValidator startupFolderValidator, + SystemFolderValidator systemFolderValidator, + FolderWritableValidator folderWritableValidator + ) + : base(signalRBroadcaster) + { + _rootFolderService = rootFolderService; + + GetResourceAll = GetRootFolders; + GetResourceById = GetRootFolder; + CreateResource = CreateRootFolder; + DeleteResource = DeleteFolder; + + SharedValidator.RuleFor(c => c.Path) + .Cascade(CascadeMode.StopOnFirstFailure) + .IsValidPath() + .SetValidator(rootFolderValidator) + .SetValidator(mappedNetworkDriveValidator) + .SetValidator(startupFolderValidator) + .SetValidator(pathExistsValidator) + .SetValidator(systemFolderValidator) + .SetValidator(folderWritableValidator); + } + + private RootFolderResource GetRootFolder(int id) + { + return _rootFolderService.Get(id).ToResource(); + } + + private int CreateRootFolder(RootFolderResource rootFolderResource) + { + var model = rootFolderResource.ToModel(); + + return _rootFolderService.Add(model).Id; + } + + private List GetRootFolders() + { + return _rootFolderService.AllWithUnmappedFolders().ToResource(); + } + + private void DeleteFolder(int id) + { + _rootFolderService.Remove(id); + } + } +} diff --git a/src/Radarr.Api.V2/RootFolders/RootFolderResource.cs b/src/Radarr.Api.V2/RootFolders/RootFolderResource.cs new file mode 100644 index 000000000..719e297b3 --- /dev/null +++ b/src/Radarr.Api.V2/RootFolders/RootFolderResource.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Core.RootFolders; +using Radarr.Http.REST; + +namespace Radarr.Api.V2.RootFolders +{ + public class RootFolderResource : RestResource + { + public string Path { get; set; } + public long? FreeSpace { get; set; } + + public List UnmappedFolders { get; set; } + } + + public static class RootFolderResourceMapper + { + public static RootFolderResource ToResource(this RootFolder model) + { + if (model == null) return null; + + return new RootFolderResource + { + Id = model.Id, + + Path = model.Path, + FreeSpace = model.FreeSpace, + UnmappedFolders = model.UnmappedFolders + }; + } + + public static RootFolder ToModel(this RootFolderResource resource) + { + if (resource == null) return null; + + return new RootFolder + { + Id = resource.Id, + + Path = resource.Path, + //FreeSpace + //UnmappedFolders + }; + } + + public static List ToResource(this IEnumerable models) + { + return models.Select(ToResource).ToList(); + } + } +} diff --git a/src/Radarr.Api.V2/System/Backup/BackupModule.cs b/src/Radarr.Api.V2/System/Backup/BackupModule.cs new file mode 100644 index 000000000..b924c48b1 --- /dev/null +++ b/src/Radarr.Api.V2/System/Backup/BackupModule.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using NzbDrone.Core.Backup; +using Radarr.Http; + +namespace Radarr.Api.V2.System.Backup +{ + public class BackupModule : RadarrRestModule + { + private readonly IBackupService _backupService; + + public BackupModule(IBackupService backupService) : base("system/backup") + { + _backupService = backupService; + GetResourceAll = GetBackupFiles; + } + + public List GetBackupFiles() + { + var backups = _backupService.GetBackups(); + + return backups.Select(b => new BackupResource + { + Id = b.Name.GetHashCode(), + Name = b.Name, + Path = $"/backup/{b.Type.ToString().ToLower()}/{b.Name}", + Type = b.Type, + Time = b.Time + }).ToList(); + } + } +} diff --git a/src/Radarr.Api.V2/System/Backup/BackupResource.cs b/src/Radarr.Api.V2/System/Backup/BackupResource.cs new file mode 100644 index 000000000..b265f423e --- /dev/null +++ b/src/Radarr.Api.V2/System/Backup/BackupResource.cs @@ -0,0 +1,14 @@ +using System; +using Radarr.Http.REST; +using NzbDrone.Core.Backup; + +namespace Radarr.Api.V2.System.Backup +{ + public class BackupResource : RestResource + { + public string Name { get; set; } + public string Path { get; set; } + public BackupType Type { get; set; } + public DateTime Time { get; set; } + } +} diff --git a/src/Radarr.Api.V2/System/SystemModule.cs b/src/Radarr.Api.V2/System/SystemModule.cs new file mode 100644 index 000000000..25b5546a1 --- /dev/null +++ b/src/Radarr.Api.V2/System/SystemModule.cs @@ -0,0 +1,95 @@ +using System.Threading.Tasks; +using Nancy; +using Nancy.Routing; +using Radarr.Http.Extensions; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Lifecycle; + +namespace Radarr.Api.V2.System +{ + public class SystemModule : RadarrV2Module + { + private readonly IAppFolderInfo _appFolderInfo; + private readonly IRuntimeInfo _runtimeInfo; + private readonly IPlatformInfo _platformInfo; + private readonly IOsInfo _osInfo; + private readonly IRouteCacheProvider _routeCacheProvider; + private readonly IConfigFileProvider _configFileProvider; + private readonly IMainDatabase _database; + private readonly ILifecycleService _lifecycleService; + + public SystemModule(IAppFolderInfo appFolderInfo, + IRuntimeInfo runtimeInfo, + IPlatformInfo platformInfo, + IOsInfo osInfo, + IRouteCacheProvider routeCacheProvider, + IConfigFileProvider configFileProvider, + IMainDatabase database, + ILifecycleService lifecycleService) + : base("system") + { + _appFolderInfo = appFolderInfo; + _runtimeInfo = runtimeInfo; + _platformInfo = platformInfo; + _osInfo = osInfo; + _routeCacheProvider = routeCacheProvider; + _configFileProvider = configFileProvider; + _database = database; + _lifecycleService = lifecycleService; + Get["/status"] = x => GetStatus(); + Get["/routes"] = x => GetRoutes(); + Post["/shutdown"] = x => Shutdown(); + Post["/restart"] = x => Restart(); + } + + private Response GetStatus() + { + return new + { + Version = BuildInfo.Version.ToString(), + BuildTime = BuildInfo.BuildDateTime, + IsDebug = BuildInfo.IsDebug, + IsProduction = RuntimeInfo.IsProduction, + IsAdmin = _runtimeInfo.IsAdmin, + IsUserInteractive = RuntimeInfo.IsUserInteractive, + StartupPath = _appFolderInfo.StartUpFolder, + AppData = _appFolderInfo.GetAppDataPath(), + OsName = _osInfo.Name, + OsVersion = _osInfo.Version, + IsMonoRuntime = PlatformInfo.IsMono, + IsMono = PlatformInfo.IsMono, + IsLinux = OsInfo.IsLinux, + IsOsx = OsInfo.IsOsx, + IsWindows = OsInfo.IsWindows, + Mode = _runtimeInfo.Mode, + Branch = _configFileProvider.Branch, + Authentication = _configFileProvider.AuthenticationMethod, + SqliteVersion = _database.Version, + UrlBase = _configFileProvider.UrlBase, + RuntimeVersion = _platformInfo.Version, + RuntimeName = PlatformInfo.Platform, + StartTime = _runtimeInfo.StartTime + }.AsResponse(); + } + + private Response GetRoutes() + { + return _routeCacheProvider.GetCache().Values.AsResponse(); + } + + private Response Shutdown() + { + Task.Factory.StartNew(() => _lifecycleService.Shutdown()); + return new { ShuttingDown = true }.AsResponse(); + } + + private Response Restart() + { + Task.Factory.StartNew(() => _lifecycleService.Restart()); + return new { Restarting = true }.AsResponse(); + } + } +} diff --git a/src/Radarr.Api.V2/System/Tasks/TaskModule.cs b/src/Radarr.Api.V2/System/Tasks/TaskModule.cs new file mode 100644 index 000000000..3ba31e72b --- /dev/null +++ b/src/Radarr.Api.V2/System/Tasks/TaskModule.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Datastore.Events; +using NzbDrone.Core.Jobs; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.SignalR; +using Radarr.Http; + +namespace Radarr.Api.V2.System.Tasks +{ + public class TaskModule : RadarrRestModuleWithSignalR, IHandle + { + private readonly ITaskManager _taskManager; + + public TaskModule(ITaskManager taskManager, IBroadcastSignalRMessage broadcastSignalRMessage) + : base(broadcastSignalRMessage, "system/task") + { + _taskManager = taskManager; + GetResourceAll = GetAll; + GetResourceById = GetTask; + } + + private List GetAll() + { + return _taskManager.GetAll() + .Select(ConvertToResource) + .OrderBy(t => t.Name) + .ToList(); + } + + private TaskResource GetTask(int id) + { + var task = _taskManager.GetAll() + .SingleOrDefault(t => t.Id == id); + + if (task == null) + { + return null; + } + + return ConvertToResource(task); + } + + private static TaskResource ConvertToResource(ScheduledTask scheduledTask) + { + var taskName = scheduledTask.TypeName.Split('.').Last().Replace("Command", ""); + + return new TaskResource + { + Id = scheduledTask.Id, + Name = taskName.SplitCamelCase(), + TaskName = taskName, + Interval = scheduledTask.Interval, + LastExecution = scheduledTask.LastExecution, + NextExecution = scheduledTask.LastExecution.AddMinutes(scheduledTask.Interval) + }; + } + + public void Handle(CommandExecutedEvent message) + { + BroadcastResourceChange(ModelAction.Sync); + } + } +} diff --git a/src/Radarr.Api.V2/System/Tasks/TaskResource.cs b/src/Radarr.Api.V2/System/Tasks/TaskResource.cs new file mode 100644 index 000000000..40663dbec --- /dev/null +++ b/src/Radarr.Api.V2/System/Tasks/TaskResource.cs @@ -0,0 +1,14 @@ +using System; +using Radarr.Http.REST; + +namespace Radarr.Api.V2.System.Tasks +{ + public class TaskResource : RestResource + { + public string Name { get; set; } + public string TaskName { get; set; } + public int Interval { get; set; } + public DateTime LastExecution { get; set; } + public DateTime NextExecution { get; set; } + } +} diff --git a/src/Radarr.Api.V2/Tags/TagDetailsModule.cs b/src/Radarr.Api.V2/Tags/TagDetailsModule.cs new file mode 100644 index 000000000..d4826f5bd --- /dev/null +++ b/src/Radarr.Api.V2/Tags/TagDetailsModule.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using NzbDrone.Core.Tags; +using Radarr.Http; + +namespace Radarr.Api.V2.Tags +{ + public class TagDetailsModule : RadarrRestModule + { + private readonly ITagService _tagService; + + public TagDetailsModule(ITagService tagService) + : base("/tag/detail") + { + _tagService = tagService; + + GetResourceById = Get; + GetResourceAll = GetAll; + } + + private TagDetailsResource Get(int id) + { + return _tagService.Details(id).ToResource(); + } + + private List GetAll() + { + return _tagService.Details().ToResource(); + } + } +} diff --git a/src/Radarr.Api.V2/Tags/TagDetailsResource.cs b/src/Radarr.Api.V2/Tags/TagDetailsResource.cs new file mode 100644 index 000000000..384d2ee0b --- /dev/null +++ b/src/Radarr.Api.V2/Tags/TagDetailsResource.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Core.Tags; +using Radarr.Http.REST; + +namespace Radarr.Api.V2.Tags +{ + public class TagDetailsResource : RestResource + { + public string Label { get; set; } + public List DelayProfileIds { get; set; } + public List NotificationIds { get; set; } + public List RestrictionIds { get; set; } + public List MovieIds { get; set; } + } + + public static class TagDetailsResourceMapper + { + public static TagDetailsResource ToResource(this TagDetails model) + { + if (model == null) return null; + + return new TagDetailsResource + { + Id = model.Id, + Label = model.Label, + DelayProfileIds = model.DelayProfileIds, + NotificationIds = model.NotificationIds, + RestrictionIds = model.RestrictionIds, + MovieIds = model.MovieIds + }; + } + + public static List ToResource(this IEnumerable models) + { + return models.Select(ToResource).ToList(); + } + } +} diff --git a/src/Radarr.Api.V2/Tags/TagModule.cs b/src/Radarr.Api.V2/Tags/TagModule.cs new file mode 100644 index 000000000..8290cb4f7 --- /dev/null +++ b/src/Radarr.Api.V2/Tags/TagModule.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using NzbDrone.Core.Datastore.Events; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Tags; +using NzbDrone.SignalR; +using Radarr.Http; + +namespace Radarr.Api.V2.Tags +{ + public class TagModule : RadarrRestModuleWithSignalR, IHandle + { + private readonly ITagService _tagService; + + public TagModule(IBroadcastSignalRMessage signalRBroadcaster, + ITagService tagService) + : base(signalRBroadcaster) + { + _tagService = tagService; + + GetResourceById = Get; + GetResourceAll = GetAll; + CreateResource = Create; + UpdateResource = Update; + DeleteResource = Delete; + } + + private TagResource Get(int id) + { + return _tagService.GetTag(id).ToResource(); + } + + private List GetAll() + { + return _tagService.All().ToResource(); + } + + private int Create(TagResource resource) + { + return _tagService.Add(resource.ToModel()).Id; + } + + private void Update(TagResource resource) + { + _tagService.Update(resource.ToModel()); + } + + private void Delete(int id) + { + _tagService.Delete(id); + } + + public void Handle(TagsUpdatedEvent message) + { + BroadcastResourceChange(ModelAction.Sync); + } + } +} diff --git a/src/Radarr.Api.V2/Tags/TagResource.cs b/src/Radarr.Api.V2/Tags/TagResource.cs new file mode 100644 index 000000000..358b3705e --- /dev/null +++ b/src/Radarr.Api.V2/Tags/TagResource.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using System.Linq; +using Radarr.Http.REST; +using NzbDrone.Core.Tags; + +namespace Radarr.Api.V2.Tags +{ + public class TagResource : RestResource + { + public string Label { get; set; } + } + + public static class TagResourceMapper + { + public static TagResource ToResource(this Tag model) + { + if (model == null) return null; + + return new TagResource + { + Id = model.Id, + Label = model.Label + }; + } + + public static Tag ToModel(this TagResource resource) + { + if (resource == null) return null; + + return new Tag + { + Id = resource.Id, + Label = resource.Label + }; + } + + public static List ToResource(this IEnumerable models) + { + return models.Select(ToResource).ToList(); + } + } +} diff --git a/src/Radarr.Api.V2/Update/UpdateModule.cs b/src/Radarr.Api.V2/Update/UpdateModule.cs new file mode 100644 index 000000000..a4b718cbb --- /dev/null +++ b/src/Radarr.Api.V2/Update/UpdateModule.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Core.Update; +using Radarr.Http; + +namespace Radarr.Api.V2.Update +{ + public class UpdateModule : RadarrRestModule + { + private readonly IRecentUpdateProvider _recentUpdateProvider; + + public UpdateModule(IRecentUpdateProvider recentUpdateProvider) + { + _recentUpdateProvider = recentUpdateProvider; + GetResourceAll = GetRecentUpdates; + } + + private List GetRecentUpdates() + { + var resources = _recentUpdateProvider.GetRecentUpdatePackages() + .OrderByDescending(u => u.Version) + .ToResource(); + + if (resources.Any()) + { + var first = resources.First(); + first.Latest = true; + + if (first.Version > BuildInfo.Version) + { + first.Installable = true; + } + + var installed = resources.SingleOrDefault(r => r.Version == BuildInfo.Version); + + if (installed != null) + { + installed.Installed = true; + } + } + + return resources; + } + } +} diff --git a/src/Radarr.Api.V2/Update/UpdateResource.cs b/src/Radarr.Api.V2/Update/UpdateResource.cs new file mode 100644 index 000000000..7019ff3ae --- /dev/null +++ b/src/Radarr.Api.V2/Update/UpdateResource.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using NzbDrone.Core.Update; +using Radarr.Http.REST; + +namespace Radarr.Api.V2.Update +{ + public class UpdateResource : RestResource + { + [JsonConverter(typeof(Newtonsoft.Json.Converters.VersionConverter))] + public Version Version { get; set; } + + public string Branch { get; set; } + public DateTime ReleaseDate { get; set; } + public string FileName { get; set; } + public string Url { get; set; } + public bool Installed { get; set; } + public bool Installable { get; set; } + public bool Latest { get; set; } + public UpdateChanges Changes { get; set; } + public string Hash { get; set; } + } + + public static class UpdateResourceMapper + { + public static UpdateResource ToResource(this UpdatePackage model) + { + if (model == null) return null; + + return new UpdateResource + { + Version = model.Version, + + Branch = model.Branch, + ReleaseDate = model.ReleaseDate, + FileName = model.FileName, + Url = model.Url, + //Installed + //Installable + //Latest + Changes = model.Changes, + Hash = model.Hash, + }; + } + + public static List ToResource(this IEnumerable models) + { + return models.Select(ToResource).ToList(); + } + } +} diff --git a/src/Radarr.Api.V2/app.config b/src/Radarr.Api.V2/app.config new file mode 100644 index 000000000..d4d6857aa --- /dev/null +++ b/src/Radarr.Api.V2/app.config @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Radarr.Api.V2/packages.config b/src/Radarr.Api.V2/packages.config new file mode 100644 index 000000000..cea694345 --- /dev/null +++ b/src/Radarr.Api.V2/packages.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/NzbDrone.Api/Authentication/1tews5g3.gd1~ b/src/Radarr.Http/Authentication/1tews5g3.gd1~ similarity index 100% rename from src/NzbDrone.Api/Authentication/1tews5g3.gd1~ rename to src/Radarr.Http/Authentication/1tews5g3.gd1~ diff --git a/src/NzbDrone.Api/Authentication/AuthenticationModule.cs b/src/Radarr.Http/Authentication/AuthenticationModule.cs similarity index 89% rename from src/NzbDrone.Api/Authentication/AuthenticationModule.cs rename to src/Radarr.Http/Authentication/AuthenticationModule.cs index df940a947..d6d111172 100644 --- a/src/NzbDrone.Api/Authentication/AuthenticationModule.cs +++ b/src/Radarr.Http/Authentication/AuthenticationModule.cs @@ -7,7 +7,7 @@ using NzbDrone.Common.EnsureThat; using NzbDrone.Core.Authentication; using NzbDrone.Core.Configuration; -namespace NzbDrone.Api.Authentication +namespace Radarr.Http.Authentication { public class AuthenticationModule : NancyModule { @@ -33,7 +33,8 @@ namespace NzbDrone.Api.Authentication if (user == null) { - return Context.GetRedirect("~/login?returnUrl=" + (string)Request.Query.returnUrl); + var returnUrl = (string)Request.Query.returnUrl; + return Context.GetRedirect($"~/login?returnUrl={returnUrl}&loginFailed=true"); } DateTime? expiry = null; diff --git a/src/NzbDrone.Api/Authentication/AuthenticationService.cs b/src/Radarr.Http/Authentication/AuthenticationService.cs similarity index 95% rename from src/NzbDrone.Api/Authentication/AuthenticationService.cs rename to src/Radarr.Http/Authentication/AuthenticationService.cs index beb908b11..294f5f6d0 100644 --- a/src/NzbDrone.Api/Authentication/AuthenticationService.cs +++ b/src/Radarr.Http/Authentication/AuthenticationService.cs @@ -4,12 +4,12 @@ using Nancy; using Nancy.Authentication.Basic; using Nancy.Authentication.Forms; using Nancy.Security; -using NzbDrone.Api.Extensions; using NzbDrone.Common.Extensions; using NzbDrone.Core.Authentication; using NzbDrone.Core.Configuration; +using Radarr.Http.Extensions; -namespace NzbDrone.Api.Authentication +namespace Radarr.Http.Authentication { public interface IAuthenticationService : IUserValidator, IUserMapper { @@ -18,7 +18,6 @@ namespace NzbDrone.Api.Authentication public class AuthenticationService : IAuthenticationService { - private readonly IConfigFileProvider _configFileProvider; private readonly IUserService _userService; private static readonly NzbDroneUser AnonymousUser = new NzbDroneUser { UserName = "Anonymous" }; @@ -27,7 +26,6 @@ namespace NzbDrone.Api.Authentication public AuthenticationService(IConfigFileProvider configFileProvider, IUserService userService) { - _configFileProvider = configFileProvider; _userService = userService; API_KEY = configFileProvider.ApiKey; AUTH_METHOD = configFileProvider.AuthenticationMethod; diff --git a/src/NzbDrone.Api/Authentication/EnableAuthInNancy.cs b/src/Radarr.Http/Authentication/EnableAuthInNancy.cs similarity index 62% rename from src/NzbDrone.Api/Authentication/EnableAuthInNancy.cs rename to src/Radarr.Http/Authentication/EnableAuthInNancy.cs index e18a2a9dc..4f50c1473 100644 --- a/src/NzbDrone.Api/Authentication/EnableAuthInNancy.cs +++ b/src/Radarr.Http/Authentication/EnableAuthInNancy.cs @@ -1,22 +1,25 @@ -using System; +using System; using System.Text; using Nancy; using Nancy.Authentication.Basic; using Nancy.Authentication.Forms; using Nancy.Bootstrapper; +using Nancy.Cookies; using Nancy.Cryptography; -using NzbDrone.Api.Extensions; -using NzbDrone.Api.Extensions.Pipelines; +using NzbDrone.Common.Extensions; using NzbDrone.Core.Authentication; using NzbDrone.Core.Configuration; +using Radarr.Http.Extensions; +using Radarr.Http.Extensions.Pipelines; -namespace NzbDrone.Api.Authentication +namespace Radarr.Http.Authentication { public class EnableAuthInNancy : IRegisterNancyPipeline { private readonly IAuthenticationService _authenticationService; private readonly IConfigService _configService; private readonly IConfigFileProvider _configFileProvider; + private FormsAuthenticationConfiguration FormsAuthConfig; public EnableAuthInNancy(IAuthenticationService authenticationService, IConfigService configService, @@ -34,6 +37,7 @@ namespace NzbDrone.Api.Authentication if (_configFileProvider.AuthenticationMethod == AuthenticationType.Forms) { RegisterFormsAuth(pipelines); + pipelines.AfterRequest.AddItemToEndOfPipeline((Action)SlidingAuthenticationForFormsAuth); } else if (_configFileProvider.AuthenticationMethod == AuthenticationType.Basic) @@ -41,8 +45,8 @@ namespace NzbDrone.Api.Authentication pipelines.EnableBasicAuthentication(new BasicAuthenticationConfiguration(_authenticationService, "Radarr")); } - pipelines.BeforeRequest.AddItemToEndOfPipeline((Func) RequiresAuthentication); - pipelines.AfterRequest.AddItemToEndOfPipeline((Action) RemoveLoginHooksForApiCalls); + pipelines.BeforeRequest.AddItemToEndOfPipeline((Func)RequiresAuthentication); + pipelines.AfterRequest.AddItemToEndOfPipeline((Action)RemoveLoginHooksForApiCalls); } private Response RequiresAuthentication(NancyContext context) @@ -59,20 +63,22 @@ namespace NzbDrone.Api.Authentication private void RegisterFormsAuth(IPipelines pipelines) { + FormsAuthentication.FormsAuthenticationCookieName = "RadarrAuth"; + var cryptographyConfiguration = new CryptographyConfiguration( new RijndaelEncryptionProvider(new PassphraseKeyGenerator(_configService.RijndaelPassphrase, Encoding.ASCII.GetBytes(_configService.RijndaelSalt))), new DefaultHmacProvider(new PassphraseKeyGenerator(_configService.HmacPassphrase, Encoding.ASCII.GetBytes(_configService.HmacSalt))) ); - FormsAuthentication.FormsAuthenticationCookieName = "_ncfaradarr"; //For those people that both have sonarr and radarr. - - FormsAuthentication.Enable(pipelines, new FormsAuthenticationConfiguration + FormsAuthConfig = new FormsAuthenticationConfiguration { RedirectUrl = _configFileProvider.UrlBase + "/login", UserMapper = _authenticationService, - Path = _configFileProvider.UrlBase, + Path = GetCookiePath(), CryptographyConfiguration = cryptographyConfiguration - }); + }; + + FormsAuthentication.Enable(pipelines, FormsAuthConfig); } private void RemoveLoginHooksForApiCalls(NancyContext context) @@ -87,5 +93,43 @@ namespace NzbDrone.Api.Authentication } } } + + private void SlidingAuthenticationForFormsAuth(NancyContext context) + { + if (context.CurrentUser == null) + { + return; + } + + var formsAuthCookieName = FormsAuthentication.FormsAuthenticationCookieName; + + if (!context.Request.Path.Equals("/logout") && + context.Request.Cookies.ContainsKey(formsAuthCookieName)) + { + var formsAuthCookieValue = context.Request.Cookies[formsAuthCookieName]; + + if (FormsAuthentication.DecryptAndValidateAuthenticationCookie(formsAuthCookieValue, FormsAuthConfig).IsNotNullOrWhiteSpace()) + { + var formsAuthCookie = new NancyCookie(formsAuthCookieName, formsAuthCookieValue, true, false, DateTime.UtcNow.AddDays(7)) + { + Path = GetCookiePath() + }; + + context.Response.WithCookie(formsAuthCookie); + } + } + } + + private string GetCookiePath() + { + var urlBase = _configFileProvider.UrlBase; + + if (urlBase.IsNullOrWhiteSpace()) + { + return "/"; + } + + return urlBase; + } } } diff --git a/src/NzbDrone.Api/Authentication/LoginResource.cs b/src/Radarr.Http/Authentication/LoginResource.cs similarity index 81% rename from src/NzbDrone.Api/Authentication/LoginResource.cs rename to src/Radarr.Http/Authentication/LoginResource.cs index 5d6a5c9f5..13d2aee0b 100644 --- a/src/NzbDrone.Api/Authentication/LoginResource.cs +++ b/src/Radarr.Http/Authentication/LoginResource.cs @@ -1,4 +1,4 @@ -namespace NzbDrone.Api.Authentication +namespace Radarr.Http.Authentication { public class LoginResource { diff --git a/src/NzbDrone.Api/Authentication/NzbDroneUser.cs b/src/Radarr.Http/Authentication/NzbDroneUser.cs similarity index 85% rename from src/NzbDrone.Api/Authentication/NzbDroneUser.cs rename to src/Radarr.Http/Authentication/NzbDroneUser.cs index c8fce02fd..65297fd82 100644 --- a/src/NzbDrone.Api/Authentication/NzbDroneUser.cs +++ b/src/Radarr.Http/Authentication/NzbDroneUser.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Nancy.Security; -namespace NzbDrone.Api.Authentication +namespace Radarr.Http.Authentication { public class NzbDroneUser : IUserIdentity { diff --git a/src/NzbDrone.Api/ClientSchema/Field.cs b/src/Radarr.Http/ClientSchema/Field.cs similarity index 63% rename from src/NzbDrone.Api/ClientSchema/Field.cs rename to src/Radarr.Http/ClientSchema/Field.cs index ec611e8d6..9ec4e7ccc 100644 --- a/src/NzbDrone.Api/ClientSchema/Field.cs +++ b/src/Radarr.Http/ClientSchema/Field.cs @@ -1,17 +1,24 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace NzbDrone.Api.ClientSchema +namespace Radarr.Http.ClientSchema { public class Field { public int Order { get; set; } public string Name { get; set; } public string Label { get; set; } + public string Unit { get; set; } public string HelpText { get; set; } public string HelpLink { get; set; } public object Value { get; set; } public string Type { get; set; } public bool Advanced { get; set; } public List SelectOptions { get; set; } + public string Section { get; set; } + + public Field Clone() + { + return (Field)MemberwiseClone(); + } } -} \ No newline at end of file +} diff --git a/src/Radarr.Http/ClientSchema/FieldMapping.cs b/src/Radarr.Http/ClientSchema/FieldMapping.cs new file mode 100644 index 000000000..420a379f6 --- /dev/null +++ b/src/Radarr.Http/ClientSchema/FieldMapping.cs @@ -0,0 +1,12 @@ +using System; + +namespace Radarr.Http.ClientSchema +{ + public class FieldMapping + { + public Field Field { get; set; } + public Type PropertyType { get; set; } + public Func GetterFunc { get; set; } + public Action SetterFunc { get; set; } + } +} diff --git a/src/Radarr.Http/ClientSchema/SchemaBuilder.cs b/src/Radarr.Http/ClientSchema/SchemaBuilder.cs new file mode 100644 index 000000000..ec629183d --- /dev/null +++ b/src/Radarr.Http/ClientSchema/SchemaBuilder.cs @@ -0,0 +1,221 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Newtonsoft.Json.Linq; +using NzbDrone.Common.EnsureThat; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Reflection; +using NzbDrone.Core.Annotations; + +namespace Radarr.Http.ClientSchema +{ + public static class SchemaBuilder + { + private static Dictionary _mappings = new Dictionary(); + + public static List ToSchema(object model) + { + Ensure.That(model, () => model).IsNotNull(); + + var mappings = GetFieldMappings(model.GetType()); + + var result = new List(mappings.Length); + + foreach (var mapping in mappings) + { + var field = mapping.Field.Clone(); + field.Value = mapping.GetterFunc(model); + + result.Add(field); + } + + return result.OrderBy(r => r.Order).ToList(); + } + + public static object ReadFromSchema(List fields, Type targetType) + { + Ensure.That(targetType, () => targetType).IsNotNull(); + + var mappings = GetFieldMappings(targetType); + + var target = Activator.CreateInstance(targetType); + + foreach (var mapping in mappings) + { + var propertyType = mapping.PropertyType; + var field = fields.Find(f => f.Name == mapping.Field.Name); + + mapping.SetterFunc(target, field.Value); + } + + return target; + + } + + public static T ReadFromSchema(List fields) + { + return (T)ReadFromSchema(fields, typeof(T)); + } + + + // Ideally this function should begin a System.Linq.Expression expression tree since it's faster. + // But it's probably not needed till performance issues pop up. + public static FieldMapping[] GetFieldMappings(Type type) + { + lock (_mappings) + { + FieldMapping[] result; + if (!_mappings.TryGetValue(type, out result)) + { + result = GetFieldMapping(type, "", v => v); + + // Renumber al the field Orders since nested settings will have dupe Orders. + for (int i = 0; i < result.Length; i++) + { + result[i].Field.Order = i; + } + + _mappings[type] = result; + } + return result; + } + } + + private static FieldMapping[] GetFieldMapping(Type type, string prefix, Func targetSelector) + { + var result = new List(); + foreach (var property in GetProperties(type)) + { + var propertyInfo = property.Item1; + if (propertyInfo.PropertyType.IsSimpleType()) + { + var fieldAttribute = property.Item2; + var field = new Field + { + Name = prefix + GetCamelCaseName(propertyInfo.Name), + Label = fieldAttribute.Label, + Unit = fieldAttribute.Unit, + HelpText = fieldAttribute.HelpText, + HelpLink = fieldAttribute.HelpLink, + Order = fieldAttribute.Order, + Advanced = fieldAttribute.Advanced, + Type = fieldAttribute.Type.ToString().ToLowerInvariant(), + Section = fieldAttribute.Section, + }; + + if (fieldAttribute.Type == FieldType.Select) + { + field.SelectOptions = GetSelectOptions(fieldAttribute.SelectOptions); + } + + var valueConverter = GetValueConverter(propertyInfo.PropertyType); + + result.Add(new FieldMapping + { + Field = field, + PropertyType = propertyInfo.PropertyType, + GetterFunc = t => propertyInfo.GetValue(targetSelector(t), null), + SetterFunc = (t, v) => propertyInfo.SetValue(targetSelector(t), valueConverter(v), null) + }); + } + else + { + result.AddRange(GetFieldMapping(propertyInfo.PropertyType, GetCamelCaseName(propertyInfo.Name) + ".", t => propertyInfo.GetValue(targetSelector(t), null))); + } + } + + return result.ToArray(); + } + + private static Tuple[] GetProperties(Type type) + { + return type.GetProperties() + .Select(v => Tuple.Create(v, v.GetAttribute(false))) + .Where(v => v.Item2 != null) + .OrderBy(v => v.Item2.Order) + .ToArray(); + } + + private static List GetSelectOptions(Type selectOptions) + { + var options = from Enum e in Enum.GetValues(selectOptions) + select new SelectOption { Value = Convert.ToInt32(e), Name = e.ToString() }; + + return options.OrderBy(o => o.Value).ToList(); + } + + private static Func GetValueConverter(Type propertyType) + { + if (propertyType == typeof(int)) + { + return fieldValue => fieldValue?.ToString().ParseInt32() ?? 0; + } + + else if (propertyType == typeof(long)) + { + return fieldValue => fieldValue?.ToString().ParseInt64() ?? 0; + } + + else if (propertyType == typeof(double)) + { + return fieldValue => fieldValue?.ToString().ParseDouble() ?? 0.0; + } + + else if (propertyType == typeof(int?)) + { + return fieldValue => fieldValue?.ToString().ParseInt32(); + } + + else if (propertyType == typeof(Int64?)) + { + return fieldValue => fieldValue?.ToString().ParseInt64(); + } + + else if (propertyType == typeof(double?)) + { + return fieldValue => fieldValue?.ToString().ParseDouble(); + } + + else if (propertyType == typeof(IEnumerable)) + { + return fieldValue => + { + if (fieldValue.GetType() == typeof(JArray)) + { + return ((JArray)fieldValue).Select(s => s.Value()); + } + else + { + return fieldValue.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => Convert.ToInt32(s)); + } + }; + } + + else if (propertyType == typeof(IEnumerable)) + { + return fieldValue => + { + if (fieldValue.GetType() == typeof(JArray)) + { + return ((JArray)fieldValue).Select(s => s.Value()); + } + else + { + return fieldValue.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + } + }; + } + + else + { + return fieldValue => fieldValue; + } + } + + private static string GetCamelCaseName(string name) + { + return Char.ToLowerInvariant(name[0]) + name.Substring(1); + } + } +} diff --git a/src/NzbDrone.Api/ClientSchema/SelectOption.cs b/src/Radarr.Http/ClientSchema/SelectOption.cs similarity index 76% rename from src/NzbDrone.Api/ClientSchema/SelectOption.cs rename to src/Radarr.Http/ClientSchema/SelectOption.cs index fe42f46dd..94975fa7b 100644 --- a/src/NzbDrone.Api/ClientSchema/SelectOption.cs +++ b/src/Radarr.Http/ClientSchema/SelectOption.cs @@ -1,4 +1,4 @@ -namespace NzbDrone.Api.ClientSchema +namespace Radarr.Http.ClientSchema { public class SelectOption { diff --git a/src/NzbDrone.Api/ErrorManagement/ErrorHandler.cs b/src/Radarr.Http/ErrorManagement/ErrorHandler.cs similarity index 93% rename from src/NzbDrone.Api/ErrorManagement/ErrorHandler.cs rename to src/Radarr.Http/ErrorManagement/ErrorHandler.cs index 6ba25d741..dd528ea31 100644 --- a/src/NzbDrone.Api/ErrorManagement/ErrorHandler.cs +++ b/src/Radarr.Http/ErrorManagement/ErrorHandler.cs @@ -1,8 +1,8 @@ using Nancy; using Nancy.ErrorHandling; -using NzbDrone.Api.Extensions; +using Radarr.Http.Extensions; -namespace NzbDrone.Api.ErrorManagement +namespace Radarr.Http.ErrorManagement { public class ErrorHandler : IStatusCodeHandler { diff --git a/src/NzbDrone.Api/ErrorManagement/ErrorModel.cs b/src/Radarr.Http/ErrorManagement/ErrorModel.cs similarity index 83% rename from src/NzbDrone.Api/ErrorManagement/ErrorModel.cs rename to src/Radarr.Http/ErrorManagement/ErrorModel.cs index b88600717..390758f1e 100644 --- a/src/NzbDrone.Api/ErrorManagement/ErrorModel.cs +++ b/src/Radarr.Http/ErrorManagement/ErrorModel.cs @@ -1,4 +1,6 @@ -namespace NzbDrone.Api.ErrorManagement +using Radarr.Http.Exceptions; + +namespace Radarr.Http.ErrorManagement { public class ErrorModel { diff --git a/src/NzbDrone.Api/ErrorManagement/NzbDroneErrorPipeline.cs b/src/Radarr.Http/ErrorManagement/RadarrErrorPipeline.cs similarity index 76% rename from src/NzbDrone.Api/ErrorManagement/NzbDroneErrorPipeline.cs rename to src/Radarr.Http/ErrorManagement/RadarrErrorPipeline.cs index f65473cf0..9542e7902 100644 --- a/src/NzbDrone.Api/ErrorManagement/NzbDroneErrorPipeline.cs +++ b/src/Radarr.Http/ErrorManagement/RadarrErrorPipeline.cs @@ -1,19 +1,20 @@ using System; using System.Data.SQLite; using FluentValidation; -using NLog; using Nancy; -using NzbDrone.Api.Extensions; +using NLog; using NzbDrone.Core.Exceptions; +using Radarr.Http.Exceptions; +using Radarr.Http.Extensions; using HttpStatusCode = Nancy.HttpStatusCode; -namespace NzbDrone.Api.ErrorManagement +namespace Radarr.Http.ErrorManagement { - public class NzbDroneErrorPipeline + public class RadarrErrorPipeline { private readonly Logger _logger; - public NzbDroneErrorPipeline(Logger logger) + public RadarrErrorPipeline(Logger logger) { _logger = logger; } @@ -63,18 +64,16 @@ namespace NzbDrone.Api.ErrorManagement }.AsResponse(HttpStatusCode.Conflict); } - var sqlErrorMessage = string.Format("[{0} {1}]", context.Request.Method, context.Request.Path); - - _logger.Error(sqLiteException, sqlErrorMessage); + _logger.Error(sqLiteException, "[{0} {1}]", context.Request.Method, context.Request.Path); } - - _logger.Fatal(exception, "Request Failed"); + + _logger.Fatal(exception, "Request Failed. {0} {1}", context.Request.Method, context.Request.Path); return new ErrorModel - { - Message = exception.Message, - Description = exception.ToString() - }.AsResponse(HttpStatusCode.InternalServerError); + { + Message = exception.Message, + Description = exception.ToString() + }.AsResponse(HttpStatusCode.InternalServerError); } } } \ No newline at end of file diff --git a/src/NzbDrone.Api/ErrorManagement/ApiException.cs b/src/Radarr.Http/Exceptions/ApiException.cs similarity index 90% rename from src/NzbDrone.Api/ErrorManagement/ApiException.cs rename to src/Radarr.Http/Exceptions/ApiException.cs index 2a9f2678f..09175db4a 100644 --- a/src/NzbDrone.Api/ErrorManagement/ApiException.cs +++ b/src/Radarr.Http/Exceptions/ApiException.cs @@ -1,9 +1,10 @@ using System; using Nancy; using Nancy.Responses; -using NzbDrone.Api.Extensions; +using Radarr.Http.ErrorManagement; +using Radarr.Http.Extensions; -namespace NzbDrone.Api.ErrorManagement +namespace Radarr.Http.Exceptions { public abstract class ApiException : Exception { diff --git a/src/NzbDrone.Api/Exceptions/InvalidApiKeyException.cs b/src/Radarr.Http/Exceptions/InvalidApiKeyException.cs similarity index 87% rename from src/NzbDrone.Api/Exceptions/InvalidApiKeyException.cs rename to src/Radarr.Http/Exceptions/InvalidApiKeyException.cs index 8c16e8133..d6306a5d0 100644 --- a/src/NzbDrone.Api/Exceptions/InvalidApiKeyException.cs +++ b/src/Radarr.Http/Exceptions/InvalidApiKeyException.cs @@ -1,6 +1,6 @@ using System; -namespace NzbDrone.Api.Exceptions +namespace Radarr.Http.Exceptions { public class InvalidApiKeyException : Exception { diff --git a/src/NzbDrone.Api/Extensions/AccessControlHeaders.cs b/src/Radarr.Http/Extensions/AccessControlHeaders.cs similarity index 92% rename from src/NzbDrone.Api/Extensions/AccessControlHeaders.cs rename to src/Radarr.Http/Extensions/AccessControlHeaders.cs index 5a32395cb..c86f35232 100644 --- a/src/NzbDrone.Api/Extensions/AccessControlHeaders.cs +++ b/src/Radarr.Http/Extensions/AccessControlHeaders.cs @@ -1,4 +1,4 @@ -namespace NzbDrone.Api.Extensions +namespace Radarr.Http.Extensions { public static class AccessControlHeaders { diff --git a/src/NzbDrone.Api/Extensions/NancyJsonSerializer.cs b/src/Radarr.Http/Extensions/NancyJsonSerializer.cs similarity index 93% rename from src/NzbDrone.Api/Extensions/NancyJsonSerializer.cs rename to src/Radarr.Http/Extensions/NancyJsonSerializer.cs index 00b3c3b2c..971cedfaf 100644 --- a/src/NzbDrone.Api/Extensions/NancyJsonSerializer.cs +++ b/src/Radarr.Http/Extensions/NancyJsonSerializer.cs @@ -3,7 +3,7 @@ using System.IO; using Nancy; using NzbDrone.Common.Serializer; -namespace NzbDrone.Api.Extensions +namespace Radarr.Http.Extensions { public class NancyJsonSerializer : ISerializer { diff --git a/src/NzbDrone.Api/Extensions/Pipelines/CacheHeaderPipeline.cs b/src/Radarr.Http/Extensions/Pipelines/CacheHeaderPipeline.cs similarity index 92% rename from src/NzbDrone.Api/Extensions/Pipelines/CacheHeaderPipeline.cs rename to src/Radarr.Http/Extensions/Pipelines/CacheHeaderPipeline.cs index d8e9266ad..77befa3b1 100644 --- a/src/NzbDrone.Api/Extensions/Pipelines/CacheHeaderPipeline.cs +++ b/src/Radarr.Http/Extensions/Pipelines/CacheHeaderPipeline.cs @@ -1,9 +1,9 @@ using System; using Nancy; using Nancy.Bootstrapper; -using NzbDrone.Api.Frontend; +using Radarr.Http.Frontend; -namespace NzbDrone.Api.Extensions.Pipelines +namespace Radarr.Http.Extensions.Pipelines { public class CacheHeaderPipeline : IRegisterNancyPipeline { diff --git a/src/NzbDrone.Api/Extensions/Pipelines/CorsPipeline.cs b/src/Radarr.Http/Extensions/Pipelines/CorsPipeline.cs similarity index 93% rename from src/NzbDrone.Api/Extensions/Pipelines/CorsPipeline.cs rename to src/Radarr.Http/Extensions/Pipelines/CorsPipeline.cs index b63c2f19b..d2c8783dc 100644 --- a/src/NzbDrone.Api/Extensions/Pipelines/CorsPipeline.cs +++ b/src/Radarr.Http/Extensions/Pipelines/CorsPipeline.cs @@ -1,10 +1,10 @@ -using System; +using System; using System.Linq; using Nancy; using Nancy.Bootstrapper; using NzbDrone.Common.Extensions; -namespace NzbDrone.Api.Extensions.Pipelines +namespace Radarr.Http.Extensions.Pipelines { public class CorsPipeline : IRegisterNancyPipeline { @@ -71,7 +71,7 @@ namespace NzbDrone.Api.Extensions.Pipelines if (request.Headers[AccessControlHeaders.RequestHeaders].Any()) { - var requestedHeaders = string.Join(", ", request.Headers[AccessControlHeaders.RequestHeaders]); + var requestedHeaders = request.Headers[AccessControlHeaders.RequestHeaders].Join(", "); response.Headers.Add(AccessControlHeaders.AllowHeaders, requestedHeaders); } diff --git a/src/NzbDrone.Api/Extensions/Pipelines/GZipPipeline.cs b/src/Radarr.Http/Extensions/Pipelines/GZipPipeline.cs similarity index 94% rename from src/NzbDrone.Api/Extensions/Pipelines/GZipPipeline.cs rename to src/Radarr.Http/Extensions/Pipelines/GZipPipeline.cs index 26278c054..e2ff93cff 100644 --- a/src/NzbDrone.Api/Extensions/Pipelines/GZipPipeline.cs +++ b/src/Radarr.Http/Extensions/Pipelines/GZipPipeline.cs @@ -8,7 +8,7 @@ using NLog; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; -namespace NzbDrone.Api.Extensions.Pipelines +namespace Radarr.Http.Extensions.Pipelines { public class GzipCompressionPipeline : IRegisterNancyPipeline { @@ -23,7 +23,7 @@ namespace NzbDrone.Api.Extensions.Pipelines _logger = logger; // On Mono GZipStream/DeflateStream leaks memory if an exception is thrown, use an intermediate buffer in that case. - _writeGZipStream = OsInfo.IsMonoRuntime ? WriteGZipStreamMono : (Action, Stream>)WriteGZipStream; + _writeGZipStream = PlatformInfo.IsMono ? WriteGZipStreamMono : (Action, Stream>)WriteGZipStream; } public void Register(IPipelines pipelines) @@ -82,20 +82,24 @@ namespace NzbDrone.Api.Extensions.Pipelines private static bool ContentLengthIsTooSmall(Response response) { var contentLength = response.Headers.GetValueOrDefault("Content-Length"); + if (contentLength != null && long.Parse(contentLength) < 1024) { return true; } + return false; } private static bool AlreadyGzipEncoded(Response response) { var contentEncoding = response.Headers.GetValueOrDefault("Content-Encoding"); + if (contentEncoding == "gzip") { return true; } + return false; } } diff --git a/src/NzbDrone.Api/Extensions/Pipelines/IRegisterNancyPipeline.cs b/src/Radarr.Http/Extensions/Pipelines/IRegisterNancyPipeline.cs similarity index 78% rename from src/NzbDrone.Api/Extensions/Pipelines/IRegisterNancyPipeline.cs rename to src/Radarr.Http/Extensions/Pipelines/IRegisterNancyPipeline.cs index 0376ccc70..ca348df69 100644 --- a/src/NzbDrone.Api/Extensions/Pipelines/IRegisterNancyPipeline.cs +++ b/src/Radarr.Http/Extensions/Pipelines/IRegisterNancyPipeline.cs @@ -1,6 +1,6 @@ using Nancy.Bootstrapper; -namespace NzbDrone.Api.Extensions.Pipelines +namespace Radarr.Http.Extensions.Pipelines { public interface IRegisterNancyPipeline { diff --git a/src/NzbDrone.Api/Extensions/Pipelines/IfModifiedPipeline.cs b/src/Radarr.Http/Extensions/Pipelines/IfModifiedPipeline.cs similarity index 93% rename from src/NzbDrone.Api/Extensions/Pipelines/IfModifiedPipeline.cs rename to src/Radarr.Http/Extensions/Pipelines/IfModifiedPipeline.cs index 68abf4ade..58ae5e9e1 100644 --- a/src/NzbDrone.Api/Extensions/Pipelines/IfModifiedPipeline.cs +++ b/src/Radarr.Http/Extensions/Pipelines/IfModifiedPipeline.cs @@ -1,9 +1,9 @@ using System; using Nancy; using Nancy.Bootstrapper; -using NzbDrone.Api.Frontend; +using Radarr.Http.Frontend; -namespace NzbDrone.Api.Extensions.Pipelines +namespace Radarr.Http.Extensions.Pipelines { public class IfModifiedPipeline : IRegisterNancyPipeline { diff --git a/src/NzbDrone.Api/Extensions/Pipelines/NzbDroneVersionPipeline.cs b/src/Radarr.Http/Extensions/Pipelines/RadarrVersionPipeline.cs similarity index 81% rename from src/NzbDrone.Api/Extensions/Pipelines/NzbDroneVersionPipeline.cs rename to src/Radarr.Http/Extensions/Pipelines/RadarrVersionPipeline.cs index 00488657b..c71c927b8 100644 --- a/src/NzbDrone.Api/Extensions/Pipelines/NzbDroneVersionPipeline.cs +++ b/src/Radarr.Http/Extensions/Pipelines/RadarrVersionPipeline.cs @@ -1,11 +1,11 @@ -using System; +using System; using Nancy; using Nancy.Bootstrapper; using NzbDrone.Common.EnvironmentInfo; -namespace NzbDrone.Api.Extensions.Pipelines +namespace Radarr.Http.Extensions.Pipelines { - public class NzbDroneVersionPipeline : IRegisterNancyPipeline + public class RadarrVersionPipeline : IRegisterNancyPipeline { public int Order => 0; @@ -22,4 +22,4 @@ namespace NzbDrone.Api.Extensions.Pipelines } } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Extensions/Pipelines/RequestLoggingPipeline.cs b/src/Radarr.Http/Extensions/Pipelines/RequestLoggingPipeline.cs similarity index 89% rename from src/NzbDrone.Api/Extensions/Pipelines/RequestLoggingPipeline.cs rename to src/Radarr.Http/Extensions/Pipelines/RequestLoggingPipeline.cs index 918d8db5e..f369c4e9a 100644 --- a/src/NzbDrone.Api/Extensions/Pipelines/RequestLoggingPipeline.cs +++ b/src/Radarr.Http/Extensions/Pipelines/RequestLoggingPipeline.cs @@ -1,84 +1,93 @@ -using System; -using System.Threading; -using Nancy; -using Nancy.Bootstrapper; -using NLog; -using NzbDrone.Api.ErrorManagement; -using NzbDrone.Common.Extensions; - -namespace NzbDrone.Api.Extensions.Pipelines -{ - public class RequestLoggingPipeline : IRegisterNancyPipeline - { - private static readonly Logger _loggerHttp = LogManager.GetLogger("Http"); - private static readonly Logger _loggerApi = LogManager.GetLogger("Api"); - - private static int _requestSequenceID; - - private readonly NzbDroneErrorPipeline _errorPipeline; - - public RequestLoggingPipeline(NzbDroneErrorPipeline errorPipeline) - { - _errorPipeline = errorPipeline; - } - - public int Order => 100; - - public void Register(IPipelines pipelines) - { - pipelines.BeforeRequest.AddItemToStartOfPipeline(LogStart); - pipelines.AfterRequest.AddItemToEndOfPipeline(LogEnd); - pipelines.OnError.AddItemToEndOfPipeline(LogError); - } - - private Response LogStart(NancyContext context) - { - var id = Interlocked.Increment(ref _requestSequenceID); - - context.Items["ApiRequestSequenceID"] = id; - context.Items["ApiRequestStartTime"] = DateTime.UtcNow; - - var reqPath = GetRequestPathAndQuery(context.Request); - - _loggerHttp.Trace("Req: {0} [{1}] {2}", id, context.Request.Method, reqPath); - - return null; - } - - private void LogEnd(NancyContext context) - { - var id = (int)context.Items["ApiRequestSequenceID"]; - var startTime = (DateTime)context.Items["ApiRequestStartTime"]; - - var endTime = DateTime.UtcNow; - var duration = endTime - startTime; - - var reqPath = GetRequestPathAndQuery(context.Request); - - _loggerHttp.Trace("Res: {0} [{1}] {2}: {3}.{4} ({5} ms)", id, context.Request.Method, reqPath, (int)context.Response.StatusCode, context.Response.StatusCode, (int)duration.TotalMilliseconds); - - if (context.Request.IsApiRequest()) - { - _loggerApi.Debug("[{0}] {1}: {2}.{3} ({4} ms)", context.Request.Method, reqPath, (int)context.Response.StatusCode, context.Response.StatusCode, (int)duration.TotalMilliseconds); - } - } - - private Response LogError(NancyContext context, Exception exception) - { - var response = _errorPipeline.HandleException(context, exception); - context.Response = response; - LogEnd(context); - context.Response = null; - return response; - } - - private static string GetRequestPathAndQuery(Request request) - { - if (request.Url.Query.IsNotNullOrWhiteSpace()) - { - return string.Concat(request.Url.Path, request.Url.Query); - } - return request.Url.Path; - } - } -} \ No newline at end of file +using System; +using System.Threading; +using Nancy; +using Nancy.Bootstrapper; +using NLog; +using NzbDrone.Common.Extensions; +using Radarr.Http.ErrorManagement; +using Radarr.Http.Extensions; +using Radarr.Http.Extensions.Pipelines; + +namespace NzbDrone.Api.Extensions.Pipelines +{ + public class RequestLoggingPipeline : IRegisterNancyPipeline + { + private static readonly Logger _loggerHttp = LogManager.GetLogger("Http"); + private static readonly Logger _loggerApi = LogManager.GetLogger("Api"); + + private static int _requestSequenceID; + + private readonly RadarrErrorPipeline _errorPipeline; + + public RequestLoggingPipeline(RadarrErrorPipeline errorPipeline) + { + _errorPipeline = errorPipeline; + } + + public int Order => 100; + + public void Register(IPipelines pipelines) + { + pipelines.BeforeRequest.AddItemToStartOfPipeline(LogStart); + pipelines.AfterRequest.AddItemToEndOfPipeline(LogEnd); + pipelines.OnError.AddItemToEndOfPipeline(LogError); + } + + private Response LogStart(NancyContext context) + { + var id = Interlocked.Increment(ref _requestSequenceID); + + context.Items["ApiRequestSequenceID"] = id; + context.Items["ApiRequestStartTime"] = DateTime.UtcNow; + + var reqPath = GetRequestPathAndQuery(context.Request); + + _loggerHttp.Trace("Req: {0} [{1}] {2}", id, context.Request.Method, reqPath); + + return null; + } + + private void LogEnd(NancyContext context) + { + var id = (int)context.Items["ApiRequestSequenceID"]; + var startTime = (DateTime)context.Items["ApiRequestStartTime"]; + + var endTime = DateTime.UtcNow; + var duration = endTime - startTime; + + var reqPath = GetRequestPathAndQuery(context.Request); + + _loggerHttp.Trace("Res: {0} [{1}] {2}: {3}.{4} ({5} ms)", id, context.Request.Method, reqPath, (int)context.Response.StatusCode, context.Response.StatusCode, (int)duration.TotalMilliseconds); + + if (context.Request.IsApiRequest()) + { + _loggerApi.Debug("[{0}] {1}: {2}.{3} ({4} ms)", context.Request.Method, reqPath, (int)context.Response.StatusCode, context.Response.StatusCode, (int)duration.TotalMilliseconds); + } + } + + private Response LogError(NancyContext context, Exception exception) + { + var response = _errorPipeline.HandleException(context, exception); + + context.Response = response; + + LogEnd(context); + + context.Response = null; + + return response; + } + + private static string GetRequestPathAndQuery(Request request) + { + if (request.Url.Query.IsNotNullOrWhiteSpace()) + { + return string.Concat(request.Url.Path, request.Url.Query); + } + else + { + return request.Url.Path; + } + } + } +} diff --git a/src/NzbDrone.Api/Extensions/Pipelines/UrlBasePipeline.cs b/src/Radarr.Http/Extensions/Pipelines/UrlBasePipeline.cs similarity index 94% rename from src/NzbDrone.Api/Extensions/Pipelines/UrlBasePipeline.cs rename to src/Radarr.Http/Extensions/Pipelines/UrlBasePipeline.cs index d8c765e67..9d7768a78 100644 --- a/src/NzbDrone.Api/Extensions/Pipelines/UrlBasePipeline.cs +++ b/src/Radarr.Http/Extensions/Pipelines/UrlBasePipeline.cs @@ -1,11 +1,11 @@ -using System; +using System; using Nancy; using Nancy.Bootstrapper; using Nancy.Responses; using NzbDrone.Common.Extensions; using NzbDrone.Core.Configuration; -namespace NzbDrone.Api.Extensions.Pipelines +namespace Radarr.Http.Extensions.Pipelines { public class UrlBasePipeline : IRegisterNancyPipeline { @@ -43,4 +43,4 @@ namespace NzbDrone.Api.Extensions.Pipelines return null; } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Extensions/ReqResExtensions.cs b/src/Radarr.Http/Extensions/ReqResExtensions.cs similarity index 98% rename from src/NzbDrone.Api/Extensions/ReqResExtensions.cs rename to src/Radarr.Http/Extensions/ReqResExtensions.cs index 1f1d89180..1bd84cb66 100644 --- a/src/NzbDrone.Api/Extensions/ReqResExtensions.cs +++ b/src/Radarr.Http/Extensions/ReqResExtensions.cs @@ -6,7 +6,7 @@ using Nancy.Responses; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Serializer; -namespace NzbDrone.Api.Extensions +namespace Radarr.Http.Extensions { public static class ReqResExtensions { diff --git a/src/NzbDrone.Api/Extensions/RequestExtensions.cs b/src/Radarr.Http/Extensions/RequestExtensions.cs similarity index 79% rename from src/NzbDrone.Api/Extensions/RequestExtensions.cs rename to src/Radarr.Http/Extensions/RequestExtensions.cs index 925070036..20f9e4f57 100644 --- a/src/NzbDrone.Api/Extensions/RequestExtensions.cs +++ b/src/Radarr.Http/Extensions/RequestExtensions.cs @@ -1,7 +1,7 @@ -using System; +using System; using Nancy; -namespace NzbDrone.Api.Extensions +namespace Radarr.Http.Extensions { public static class RequestExtensions { @@ -42,5 +42,17 @@ namespace NzbDrone.Api.Extensions return request.Path.StartsWith("/MediaCover/", StringComparison.InvariantCultureIgnoreCase) || request.Path.StartsWith("/Content/Images/", StringComparison.InvariantCultureIgnoreCase); } + + public static bool GetBooleanQueryParameter(this Request request, string parameter, bool defaultValue = false) + { + var parameterValue = request.Query[parameter]; + + if (parameterValue.HasValue) + { + return bool.Parse(parameterValue.Value); + } + + return defaultValue; + } } } diff --git a/src/NzbDrone.Api/Frontend/CacheableSpecification.cs b/src/Radarr.Http/Frontend/CacheableSpecification.cs similarity index 89% rename from src/NzbDrone.Api/Frontend/CacheableSpecification.cs rename to src/Radarr.Http/Frontend/CacheableSpecification.cs index 3affedbf0..7ef86febe 100644 --- a/src/NzbDrone.Api/Frontend/CacheableSpecification.cs +++ b/src/Radarr.Http/Frontend/CacheableSpecification.cs @@ -3,7 +3,7 @@ using Nancy; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; -namespace NzbDrone.Api.Frontend +namespace Radarr.Http.Frontend { public interface ICacheableSpecification { @@ -29,7 +29,8 @@ namespace NzbDrone.Api.Frontend } if (context.Request.Path.StartsWith("/signalr", StringComparison.CurrentCultureIgnoreCase)) return false; - if (context.Request.Path.EndsWith("main.js")) return false; + if (context.Request.Path.EndsWith("index.js")) return false; + if (context.Request.Path.EndsWith("initialize.js")) return false; if (context.Request.Path.StartsWith("/feed", StringComparison.CurrentCultureIgnoreCase)) return false; if (context.Request.Path.StartsWith("/log", StringComparison.CurrentCultureIgnoreCase) && diff --git a/src/Radarr.Http/Frontend/InitializeJsModule.cs b/src/Radarr.Http/Frontend/InitializeJsModule.cs new file mode 100644 index 000000000..d0fa9f26b --- /dev/null +++ b/src/Radarr.Http/Frontend/InitializeJsModule.cs @@ -0,0 +1,75 @@ +using System.IO; +using System.Text; +using Nancy; +using Nancy.Responses; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Core.Analytics; +using NzbDrone.Core.Configuration; + +namespace Radarr.Http.Frontend +{ + public class InitializeJsModule : NancyModule + { + private readonly IConfigFileProvider _configFileProvider; + private readonly IAnalyticsService _analyticsService; + + private static string _apiKey; + private static string _urlBase; + private string _generatedContent; + + public InitializeJsModule(IConfigFileProvider configFileProvider, + IAnalyticsService analyticsService) + { + _configFileProvider = configFileProvider; + _analyticsService = analyticsService; + + _apiKey = configFileProvider.ApiKey; + _urlBase = configFileProvider.UrlBase; + + Get["/initialize.js"] = x => Index(); + } + + private Response Index() + { + // TODO: Move away from window.Sonarr and prefetch the information returned here when starting the UI + return new StreamResponse(GetContentStream, "application/javascript"); + } + + private Stream GetContentStream() + { + var text = GetContent(); + + var stream = new MemoryStream(); + var writer = new StreamWriter(stream); + writer.Write(text); + writer.Flush(); + stream.Position = 0; + + return stream; + } + + private string GetContent() + { + if (RuntimeInfo.IsProduction && _generatedContent != null) + { + return _generatedContent; + } + + var builder = new StringBuilder(); + builder.AppendLine("window.Radarr = {"); + builder.AppendLine($" apiRoot: '{_urlBase}/api/v2',"); + builder.AppendLine($" apiKey: '{_apiKey}',"); + builder.AppendLine($" release: '{BuildInfo.Release}',"); + builder.AppendLine($" version: '{BuildInfo.Version.ToString()}',"); + builder.AppendLine($" branch: '{_configFileProvider.Branch.ToLower()}',"); + builder.AppendLine($" analytics: {_analyticsService.IsEnabled.ToString().ToLowerInvariant()},"); + builder.AppendLine($" urlBase: '{_urlBase}',"); + builder.AppendLine($" isProduction: {RuntimeInfo.IsProduction.ToString().ToLowerInvariant()}"); + builder.AppendLine("};"); + + _generatedContent = builder.ToString(); + + return _generatedContent; + } + } +} diff --git a/src/NzbDrone.Api/Frontend/Mappers/BackupFileMapper.cs b/src/Radarr.Http/Frontend/Mappers/BackupFileMapper.cs similarity index 59% rename from src/NzbDrone.Api/Frontend/Mappers/BackupFileMapper.cs rename to src/Radarr.Http/Frontend/Mappers/BackupFileMapper.cs index 8e8393ef6..0a0afa951 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/BackupFileMapper.cs +++ b/src/Radarr.Http/Frontend/Mappers/BackupFileMapper.cs @@ -2,30 +2,31 @@ using System.IO; using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; -using NzbDrone.Common.Extensions; +using NzbDrone.Core.Backup; -namespace NzbDrone.Api.Frontend.Mappers +namespace Radarr.Http.Frontend.Mappers { public class BackupFileMapper : StaticResourceMapperBase { + private readonly IBackupService _backupService; private readonly IAppFolderInfo _appFolderInfo; - public BackupFileMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, Logger logger) + public BackupFileMapper(IBackupService backupService, IDiskProvider diskProvider, Logger logger) : base(diskProvider, logger) { - _appFolderInfo = appFolderInfo; + _backupService = backupService; } public override string Map(string resourceUrl) { var path = resourceUrl.Replace("/backup/", "").Replace('/', Path.DirectorySeparatorChar); - return Path.Combine(_appFolderInfo.GetBackupFolder(), path); + return Path.Combine(_backupService.GetBackupFolder(), path); } public override bool CanHandle(string resourceUrl) { - return resourceUrl.StartsWith("/backup/") && resourceUrl.ContainsIgnoreCase("radarr_backup_") && resourceUrl.EndsWith(".zip"); + return resourceUrl.StartsWith("/backup/") && BackupService.BackupFileRegex.IsMatch(resourceUrl); } } -} \ No newline at end of file +} diff --git a/src/Radarr.Http/Frontend/Mappers/BrowserConfig.cs b/src/Radarr.Http/Frontend/Mappers/BrowserConfig.cs new file mode 100644 index 000000000..c0c592cbc --- /dev/null +++ b/src/Radarr.Http/Frontend/Mappers/BrowserConfig.cs @@ -0,0 +1,34 @@ +using System.IO; +using NLog; +using NzbDrone.Common.Disk; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Core.Configuration; + +namespace Radarr.Http.Frontend.Mappers +{ + public class BrowserConfig : StaticResourceMapperBase + { + private readonly IAppFolderInfo _appFolderInfo; + private readonly IConfigFileProvider _configFileProvider; + + public BrowserConfig(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger) + : base(diskProvider, logger) + { + _appFolderInfo = appFolderInfo; + _configFileProvider = configFileProvider; + } + + public override string Map(string resourceUrl) + { + var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar); + path = path.Trim(Path.DirectorySeparatorChar); + + return Path.ChangeExtension(Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path), "xml"); + } + + public override bool CanHandle(string resourceUrl) + { + return resourceUrl.StartsWith("/content/images/icons/browserconfig"); + } + } +} diff --git a/src/NzbDrone.Api/Frontend/Mappers/CacheBreakerProvider.cs b/src/Radarr.Http/Frontend/Mappers/CacheBreakerProvider.cs similarity index 96% rename from src/NzbDrone.Api/Frontend/Mappers/CacheBreakerProvider.cs rename to src/Radarr.Http/Frontend/Mappers/CacheBreakerProvider.cs index 53ebb2986..9f753c73e 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/CacheBreakerProvider.cs +++ b/src/Radarr.Http/Frontend/Mappers/CacheBreakerProvider.cs @@ -3,7 +3,7 @@ using System.Linq; using NzbDrone.Common.Crypto; using NzbDrone.Common.Extensions; -namespace NzbDrone.Api.Frontend.Mappers +namespace Radarr.Http.Frontend.Mappers { public interface ICacheBreakerProvider { diff --git a/src/NzbDrone.Api/Frontend/Mappers/FaviconMapper.cs b/src/Radarr.Http/Frontend/Mappers/FaviconMapper.cs similarity index 88% rename from src/NzbDrone.Api/Frontend/Mappers/FaviconMapper.cs rename to src/Radarr.Http/Frontend/Mappers/FaviconMapper.cs index 002ffa7ce..f2ae3fef1 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/FaviconMapper.cs +++ b/src/Radarr.Http/Frontend/Mappers/FaviconMapper.cs @@ -1,10 +1,10 @@ -using System.IO; +using System.IO; using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Core.Configuration; -namespace NzbDrone.Api.Frontend.Mappers +namespace Radarr.Http.Frontend.Mappers { public class FaviconMapper : StaticResourceMapperBase { @@ -27,7 +27,7 @@ namespace NzbDrone.Api.Frontend.Mappers fileName = "favicon-debug.ico"; } - var path = Path.Combine("Content", "Images", fileName); + var path = Path.Combine("Content", "Images", "Icons", fileName); return Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path); } diff --git a/src/Radarr.Http/Frontend/Mappers/HtmlMapperBase.cs b/src/Radarr.Http/Frontend/Mappers/HtmlMapperBase.cs new file mode 100644 index 000000000..92c70c4e4 --- /dev/null +++ b/src/Radarr.Http/Frontend/Mappers/HtmlMapperBase.cs @@ -0,0 +1,82 @@ +using System; +using System.IO; +using System.Text.RegularExpressions; +using Nancy; +using NLog; +using NzbDrone.Common.Disk; +using NzbDrone.Common.EnvironmentInfo; + +namespace Radarr.Http.Frontend.Mappers +{ + public abstract class HtmlMapperBase : StaticResourceMapperBase + { + private readonly IDiskProvider _diskProvider; + private readonly Func _cacheBreakProviderFactory; + private static readonly Regex ReplaceRegex = new Regex(@"(?:(?href|src)=\"")(?.*?(?css|js|png|ico|ics|svg))(?:\"")(?:\s(?data-no-hash))?", RegexOptions.Compiled | RegexOptions.IgnoreCase); + + private string _generatedContent; + + protected HtmlMapperBase(IDiskProvider diskProvider, + Func cacheBreakProviderFactory, + Logger logger) : base(diskProvider, logger) + { + _diskProvider = diskProvider; + _cacheBreakProviderFactory = cacheBreakProviderFactory; + } + + protected string HtmlPath; + protected string UrlBase; + + protected override Stream GetContentStream(string filePath) + { + var text = GetHtmlText(); + + var stream = new MemoryStream(); + var writer = new StreamWriter(stream); + writer.Write(text); + writer.Flush(); + stream.Position = 0; + return stream; + } + + public override Response GetResponse(string resourceUrl) + { + var response = base.GetResponse(resourceUrl); + response.Headers["X-UA-Compatible"] = "IE=edge"; + + return response; + } + + protected string GetHtmlText() + { + if (RuntimeInfo.IsProduction && _generatedContent != null) + { + return _generatedContent; + } + + var text = _diskProvider.ReadAllText(HtmlPath); + var cacheBreakProvider = _cacheBreakProviderFactory(); + + text = ReplaceRegex.Replace(text, match => + { + string url; + + if (match.Groups["nohash"].Success) + { + url = match.Groups["path"].Value; + } + + else + { + url = cacheBreakProvider.AddCacheBreakerToPath(match.Groups["path"].Value); + } + + return string.Format("{0}=\"{1}{2}\"", match.Groups["attribute"].Value, UrlBase, url); + }); + + _generatedContent = text; + + return _generatedContent; + } + } +} diff --git a/src/NzbDrone.Api/Frontend/Mappers/IMapHttpRequestsToDisk.cs b/src/Radarr.Http/Frontend/Mappers/IMapHttpRequestsToDisk.cs similarity index 84% rename from src/NzbDrone.Api/Frontend/Mappers/IMapHttpRequestsToDisk.cs rename to src/Radarr.Http/Frontend/Mappers/IMapHttpRequestsToDisk.cs index 6390a2545..aa2edb49b 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/IMapHttpRequestsToDisk.cs +++ b/src/Radarr.Http/Frontend/Mappers/IMapHttpRequestsToDisk.cs @@ -1,7 +1,7 @@  using Nancy; -namespace NzbDrone.Api.Frontend.Mappers +namespace Radarr.Http.Frontend.Mappers { public interface IMapHttpRequestsToDisk { diff --git a/src/Radarr.Http/Frontend/Mappers/IndexHtmlMapper.cs b/src/Radarr.Http/Frontend/Mappers/IndexHtmlMapper.cs new file mode 100644 index 000000000..bd8214b96 --- /dev/null +++ b/src/Radarr.Http/Frontend/Mappers/IndexHtmlMapper.cs @@ -0,0 +1,42 @@ +using System; +using System.IO; +using NLog; +using NzbDrone.Common.Disk; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Core.Configuration; + +namespace Radarr.Http.Frontend.Mappers +{ + public class IndexHtmlMapper : HtmlMapperBase + { + private readonly IConfigFileProvider _configFileProvider; + + public IndexHtmlMapper(IAppFolderInfo appFolderInfo, + IDiskProvider diskProvider, + IConfigFileProvider configFileProvider, + Func cacheBreakProviderFactory, + Logger logger) + : base(diskProvider, cacheBreakProviderFactory, logger) + { + _configFileProvider = configFileProvider; + + HtmlPath = Path.Combine(appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, "index.html"); + UrlBase = configFileProvider.UrlBase; + } + + public override string Map(string resourceUrl) + { + return HtmlPath; + } + + public override bool CanHandle(string resourceUrl) + { + resourceUrl = resourceUrl.ToLowerInvariant(); + + return !resourceUrl.StartsWith("/content") && + !resourceUrl.StartsWith("/mediacover") && + !resourceUrl.Contains(".") && + !resourceUrl.StartsWith("/login"); + } + } +} diff --git a/src/NzbDrone.Api/Frontend/Mappers/LogFileMapper.cs b/src/Radarr.Http/Frontend/Mappers/LogFileMapper.cs similarity index 95% rename from src/NzbDrone.Api/Frontend/Mappers/LogFileMapper.cs rename to src/Radarr.Http/Frontend/Mappers/LogFileMapper.cs index 5fda7d483..ee2c4e948 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/LogFileMapper.cs +++ b/src/Radarr.Http/Frontend/Mappers/LogFileMapper.cs @@ -4,7 +4,7 @@ using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; -namespace NzbDrone.Api.Frontend.Mappers +namespace Radarr.Http.Frontend.Mappers { public class UpdateLogFileMapper : StaticResourceMapperBase { diff --git a/src/Radarr.Http/Frontend/Mappers/LoginHtmlMapper.cs b/src/Radarr.Http/Frontend/Mappers/LoginHtmlMapper.cs new file mode 100644 index 000000000..4bfeb05ae --- /dev/null +++ b/src/Radarr.Http/Frontend/Mappers/LoginHtmlMapper.cs @@ -0,0 +1,34 @@ +using System; +using System.IO; +using Nancy; +using NLog; +using NzbDrone.Common.Disk; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Core.Configuration; + +namespace Radarr.Http.Frontend.Mappers +{ + public class LoginHtmlMapper : HtmlMapperBase + { + public LoginHtmlMapper(IAppFolderInfo appFolderInfo, + IDiskProvider diskProvider, + Func cacheBreakProviderFactory, + IConfigFileProvider configFileProvider, + Logger logger) + : base(diskProvider, cacheBreakProviderFactory, logger) + { + HtmlPath = Path.Combine(appFolderInfo.StartUpFolder, configFileProvider.UiFolder, "login.html"); + UrlBase = configFileProvider.UrlBase; + } + + public override string Map(string resourceUrl) + { + return HtmlPath; + } + + public override bool CanHandle(string resourceUrl) + { + return resourceUrl.StartsWith("/login"); + } + } +} diff --git a/src/Radarr.Http/Frontend/Mappers/ManifestMapper.cs b/src/Radarr.Http/Frontend/Mappers/ManifestMapper.cs new file mode 100644 index 000000000..58906f617 --- /dev/null +++ b/src/Radarr.Http/Frontend/Mappers/ManifestMapper.cs @@ -0,0 +1,34 @@ +using System.IO; +using NLog; +using NzbDrone.Common.Disk; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Core.Configuration; + +namespace Radarr.Http.Frontend.Mappers +{ + public class ManifestMapper : StaticResourceMapperBase + { + private readonly IAppFolderInfo _appFolderInfo; + private readonly IConfigFileProvider _configFileProvider; + + public ManifestMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger) + : base(diskProvider, logger) + { + _appFolderInfo = appFolderInfo; + _configFileProvider = configFileProvider; + } + + public override string Map(string resourceUrl) + { + var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar); + path = path.Trim(Path.DirectorySeparatorChar); + + return Path.ChangeExtension(Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path), "json"); + } + + public override bool CanHandle(string resourceUrl) + { + return resourceUrl.StartsWith("/Content/Images/Icons/manifest"); + } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Api/Frontend/Mappers/MediaCoverMapper.cs b/src/Radarr.Http/Frontend/Mappers/MediaCoverMapper.cs similarity index 97% rename from src/NzbDrone.Api/Frontend/Mappers/MediaCoverMapper.cs rename to src/Radarr.Http/Frontend/Mappers/MediaCoverMapper.cs index 8a5626cf2..4303de73a 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/MediaCoverMapper.cs +++ b/src/Radarr.Http/Frontend/Mappers/MediaCoverMapper.cs @@ -6,7 +6,7 @@ using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; -namespace NzbDrone.Api.Frontend.Mappers +namespace Radarr.Http.Frontend.Mappers { public class MediaCoverMapper : StaticResourceMapperBase { diff --git a/src/NzbDrone.Api/Frontend/Mappers/RobotsTxtMapper.cs b/src/Radarr.Http/Frontend/Mappers/RobotsTxtMapper.cs similarity index 96% rename from src/NzbDrone.Api/Frontend/Mappers/RobotsTxtMapper.cs rename to src/Radarr.Http/Frontend/Mappers/RobotsTxtMapper.cs index 60b3131c6..06fa10407 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/RobotsTxtMapper.cs +++ b/src/Radarr.Http/Frontend/Mappers/RobotsTxtMapper.cs @@ -4,7 +4,7 @@ using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Core.Configuration; -namespace NzbDrone.Api.Frontend.Mappers +namespace Radarr.Http.Frontend.Mappers { public class RobotsTxtMapper : StaticResourceMapperBase { diff --git a/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapper.cs b/src/Radarr.Http/Frontend/Mappers/StaticResourceMapper.cs similarity index 80% rename from src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapper.cs rename to src/Radarr.Http/Frontend/Mappers/StaticResourceMapper.cs index 4b3b939a1..fa5a424b6 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapper.cs +++ b/src/Radarr.Http/Frontend/Mappers/StaticResourceMapper.cs @@ -5,7 +5,7 @@ using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Core.Configuration; -namespace NzbDrone.Api.Frontend.Mappers +namespace Radarr.Http.Frontend.Mappers { public class StaticResourceMapper : StaticResourceMapperBase { @@ -30,9 +30,15 @@ namespace NzbDrone.Api.Frontend.Mappers public override bool CanHandle(string resourceUrl) { resourceUrl = resourceUrl.ToLowerInvariant(); + + if (resourceUrl.StartsWith("/content/images/icons/manifest") || + resourceUrl.StartsWith("/content/images/icons/browserconfig")) + { + return false; + } return resourceUrl.StartsWith("/content") || - resourceUrl.EndsWith(".js") || + (resourceUrl.EndsWith(".js") && !resourceUrl.EndsWith("initialize.js")) || resourceUrl.EndsWith(".map") || resourceUrl.EndsWith(".css") || (resourceUrl.EndsWith(".ico") && !resourceUrl.Equals("/favicon.ico")) || diff --git a/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapperBase.cs b/src/Radarr.Http/Frontend/Mappers/StaticResourceMapperBase.cs similarity index 85% rename from src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapperBase.cs rename to src/Radarr.Http/Frontend/Mappers/StaticResourceMapperBase.cs index 489d039d0..ee8a37c78 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapperBase.cs +++ b/src/Radarr.Http/Frontend/Mappers/StaticResourceMapperBase.cs @@ -1,12 +1,12 @@ using System; using System.IO; -using NLog; using Nancy; using Nancy.Responses; +using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; -namespace NzbDrone.Api.Frontend.Mappers +namespace Radarr.Http.Frontend.Mappers { public abstract class StaticResourceMapperBase : IMapHttpRequestsToDisk { @@ -21,10 +21,7 @@ namespace NzbDrone.Api.Frontend.Mappers _diskProvider = diskProvider; _logger = logger; - if (!RuntimeInfo.IsProduction) - { - _caseSensitive = StringComparison.OrdinalIgnoreCase; - } + _caseSensitive = RuntimeInfo.IsProduction ? DiskProviderBase.PathStringComparison : StringComparison.OrdinalIgnoreCase; } public abstract string Map(string resourceUrl); @@ -38,7 +35,7 @@ namespace NzbDrone.Api.Frontend.Mappers if (_diskProvider.FileExists(filePath, _caseSensitive)) { var response = new StreamResponse(() => GetContentStream(filePath), MimeTypes.GetMimeType(filePath)); - return response; + return new MaterialisingResponse(response); } _logger.Warn("File {0} not found", filePath); @@ -50,6 +47,5 @@ namespace NzbDrone.Api.Frontend.Mappers { return File.OpenRead(filePath); } - } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Api/Frontend/Mappers/UpdateLogFileMapper.cs b/src/Radarr.Http/Frontend/Mappers/UpdateLogFileMapper.cs similarity index 95% rename from src/NzbDrone.Api/Frontend/Mappers/UpdateLogFileMapper.cs rename to src/Radarr.Http/Frontend/Mappers/UpdateLogFileMapper.cs index 021bdba58..a546e04e4 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/UpdateLogFileMapper.cs +++ b/src/Radarr.Http/Frontend/Mappers/UpdateLogFileMapper.cs @@ -4,7 +4,7 @@ using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; -namespace NzbDrone.Api.Frontend.Mappers +namespace Radarr.Http.Frontend.Mappers { public class LogFileMapper : StaticResourceMapperBase { diff --git a/src/NzbDrone.Api/Frontend/StaticResourceModule.cs b/src/Radarr.Http/Frontend/StaticResourceModule.cs similarity index 79% rename from src/NzbDrone.Api/Frontend/StaticResourceModule.cs rename to src/Radarr.Http/Frontend/StaticResourceModule.cs index 270f48387..3fbde24cf 100644 --- a/src/NzbDrone.Api/Frontend/StaticResourceModule.cs +++ b/src/Radarr.Http/Frontend/StaticResourceModule.cs @@ -1,24 +1,21 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -using NLog; using Nancy; -using NzbDrone.Api.Frontend.Mappers; -using NzbDrone.Core.Configuration; +using NLog; +using Radarr.Http.Frontend.Mappers; -namespace NzbDrone.Api.Frontend +namespace Radarr.Http.Frontend { public class StaticResourceModule : NancyModule { private readonly IEnumerable _requestMappers; - private readonly IConfigFileProvider _configFileProvider; private readonly Logger _logger; - public StaticResourceModule(IEnumerable requestMappers, IConfigFileProvider configFileProvider, Logger logger) + public StaticResourceModule(IEnumerable requestMappers, Logger logger) { _requestMappers = requestMappers; - _configFileProvider = configFileProvider; _logger = logger; Get["/{resource*}"] = x => Index(); diff --git a/src/Radarr.Http/Mapping/MappingValidation.cs b/src/Radarr.Http/Mapping/MappingValidation.cs new file mode 100644 index 000000000..1433ca67f --- /dev/null +++ b/src/Radarr.Http/Mapping/MappingValidation.cs @@ -0,0 +1,54 @@ +using System; +using System.Linq; +using System.Reflection; +using NzbDrone.Common.Reflection; +using Radarr.Http.REST; + +namespace Radarr.Http.Mapping +{ + public static class MappingValidation + { + public static void ValidateMapping(Type modelType, Type resourceType) + { + var errors = modelType.GetSimpleProperties().Where(c=>!c.GetGetMethod().IsStatic).Select(p => GetError(resourceType, p)).Where(c => c != null).ToList(); + + if (errors.Any()) + { + throw new ResourceMappingException(errors); + } + + PrintExtraProperties(modelType, resourceType); + } + + private static void PrintExtraProperties(Type modelType, Type resourceType) + { + var resourceBaseProperties = typeof(RestResource).GetProperties().Select(c => c.Name); + var resourceProperties = resourceType.GetProperties().Select(c => c.Name).Except(resourceBaseProperties); + var modelProperties = modelType.GetProperties().Select(c => c.Name); + + var extra = resourceProperties.Except(modelProperties); + + foreach (var extraProp in extra) + { + Console.WriteLine("Extra: [{0}]", extraProp); + } + } + + private static string GetError(Type resourceType, PropertyInfo modelProperty) + { + var resourceProperty = resourceType.GetProperties().FirstOrDefault(c => c.Name == modelProperty.Name); + + if (resourceProperty == null) + { + return string.Format("public {0} {1} {{ get; set; }}", modelProperty.PropertyType.Name, modelProperty.Name); + } + + if (resourceProperty.PropertyType != modelProperty.PropertyType && !typeof(RestResource).IsAssignableFrom(resourceProperty.PropertyType)) + { + return string.Format("Expected {0}.{1} to have type of {2} but found {3}", resourceType.Name, resourceProperty.Name, modelProperty.PropertyType, resourceProperty.PropertyType); + } + + return null; + } + } +} \ No newline at end of file diff --git a/src/Radarr.Http/Mapping/ResourceMappingException.cs b/src/Radarr.Http/Mapping/ResourceMappingException.cs new file mode 100644 index 000000000..30128be3f --- /dev/null +++ b/src/Radarr.Http/Mapping/ResourceMappingException.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Radarr.Http.Mapping +{ + public class ResourceMappingException : ApplicationException + { + public ResourceMappingException(IEnumerable error) + : base(Environment.NewLine + string.Join(Environment.NewLine, error.OrderBy(c => c))) + { + + } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Api/PagingResource.cs b/src/Radarr.Http/PagingResource.cs similarity index 71% rename from src/NzbDrone.Api/PagingResource.cs rename to src/Radarr.Http/PagingResource.cs index d05ea2906..15a34e156 100644 --- a/src/NzbDrone.Api/PagingResource.cs +++ b/src/Radarr.Http/PagingResource.cs @@ -1,9 +1,7 @@ -using System; using System.Collections.Generic; -using System.Linq.Expressions; using NzbDrone.Core.Datastore; -namespace NzbDrone.Api +namespace Radarr.Http { public class PagingResource { @@ -11,9 +9,7 @@ namespace NzbDrone.Api public int PageSize { get; set; } public string SortKey { get; set; } public SortDirection SortDirection { get; set; } - public string FilterKey { get; set; } - public string FilterValue { get; set; } - public string FilterType { get; set; } + public List Filters { get; set; } public int TotalRecords { get; set; } public List Records { get; set; } } @@ -41,14 +37,5 @@ namespace NzbDrone.Api return pagingSpec; } - - /*public static Expression> CreateFilterExpression(string filterKey, string filterValue) - { - Type type = typeof(TModel); - ParameterExpression parameterExpression = Expression.Parameter(type, "x"); - Expression expressionBody = parameterExpression; - - return expressionBody; - }*/ } } diff --git a/src/Radarr.Http/PagingResourceFilter.cs b/src/Radarr.Http/PagingResourceFilter.cs new file mode 100644 index 000000000..13e927fa6 --- /dev/null +++ b/src/Radarr.Http/PagingResourceFilter.cs @@ -0,0 +1,8 @@ +namespace Radarr.Http +{ + public class PagingResourceFilter + { + public string Key { get; set; } + public string Value { get; set; } + } +} diff --git a/src/Radarr.Http/Properties/AssemblyInfo.cs b/src/Radarr.Http/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..94bf1aaa3 --- /dev/null +++ b/src/Radarr.Http/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Radarr.Http")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Radarr.Http")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c5953dab-89db-46d9-a401-d620f54b776e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/NzbDrone.Api/REST/BadRequestException.cs b/src/Radarr.Http/REST/BadRequestException.cs similarity index 76% rename from src/NzbDrone.Api/REST/BadRequestException.cs rename to src/Radarr.Http/REST/BadRequestException.cs index 450f484e5..b9a75c03b 100644 --- a/src/NzbDrone.Api/REST/BadRequestException.cs +++ b/src/Radarr.Http/REST/BadRequestException.cs @@ -1,7 +1,7 @@ using Nancy; -using NzbDrone.Api.ErrorManagement; +using Radarr.Http.Exceptions; -namespace NzbDrone.Api.REST +namespace Radarr.Http.REST { public class BadRequestException : ApiException { diff --git a/src/NzbDrone.Api/REST/MethodNotAllowedException.cs b/src/Radarr.Http/REST/MethodNotAllowedException.cs similarity index 78% rename from src/NzbDrone.Api/REST/MethodNotAllowedException.cs rename to src/Radarr.Http/REST/MethodNotAllowedException.cs index 44d2065c6..376458189 100644 --- a/src/NzbDrone.Api/REST/MethodNotAllowedException.cs +++ b/src/Radarr.Http/REST/MethodNotAllowedException.cs @@ -1,7 +1,7 @@ using Nancy; -using NzbDrone.Api.ErrorManagement; +using Radarr.Http.Exceptions; -namespace NzbDrone.Api.REST +namespace Radarr.Http.REST { public class MethodNotAllowedException : ApiException { diff --git a/src/NzbDrone.Api/REST/NotFoundException.cs b/src/Radarr.Http/REST/NotFoundException.cs similarity index 76% rename from src/NzbDrone.Api/REST/NotFoundException.cs rename to src/Radarr.Http/REST/NotFoundException.cs index 92b4016a9..43a457176 100644 --- a/src/NzbDrone.Api/REST/NotFoundException.cs +++ b/src/Radarr.Http/REST/NotFoundException.cs @@ -1,7 +1,7 @@ using Nancy; -using NzbDrone.Api.ErrorManagement; +using Radarr.Http.Exceptions; -namespace NzbDrone.Api.REST +namespace Radarr.Http.REST { public class NotFoundException : ApiException { diff --git a/src/NzbDrone.Api/REST/ResourceValidator.cs b/src/Radarr.Http/REST/ResourceValidator.cs similarity index 95% rename from src/NzbDrone.Api/REST/ResourceValidator.cs rename to src/Radarr.Http/REST/ResourceValidator.cs index 8062e6fd0..5127036ad 100644 --- a/src/NzbDrone.Api/REST/ResourceValidator.cs +++ b/src/Radarr.Http/REST/ResourceValidator.cs @@ -1,13 +1,13 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Linq.Expressions; using FluentValidation; using FluentValidation.Internal; using FluentValidation.Resources; -using NzbDrone.Api.ClientSchema; -using System.Linq; +using Radarr.Http.ClientSchema; -namespace NzbDrone.Api.REST +namespace Radarr.Http.REST { public class ResourceValidator : AbstractValidator { diff --git a/src/NzbDrone.Api/REST/RestModule.cs b/src/Radarr.Http/REST/RestModule.cs similarity index 76% rename from src/NzbDrone.Api/REST/RestModule.cs rename to src/Radarr.Http/REST/RestModule.cs index 419a16253..5a7c09786 100644 --- a/src/NzbDrone.Api/REST/RestModule.cs +++ b/src/Radarr.Http/REST/RestModule.cs @@ -1,12 +1,12 @@ -using System; +using System; using System.Collections.Generic; +using System.Linq; using FluentValidation; using Nancy; -using NzbDrone.Api.Extensions; -using System.Linq; using NzbDrone.Core.Datastore; +using Radarr.Http.Extensions; -namespace NzbDrone.Api.REST +namespace Radarr.Http.REST { public abstract class RestModule : NancyModule where TResource : RestResource, new() @@ -14,6 +14,16 @@ namespace NzbDrone.Api.REST private const string ROOT_ROUTE = "/"; private const string ID_ROUTE = @"/(?[\d]{1,10})"; + private HashSet EXCLUDED_KEYS = new HashSet(StringComparer.InvariantCultureIgnoreCase) + { + "page", + "pageSize", + "sortKey", + "sortDirection", + "filterKey", + "filterValue", + }; + private Action _deleteResource; private Func _getResourceById; private Func> _getResourceAll; @@ -123,13 +133,7 @@ namespace NzbDrone.Api.REST Get[ROOT_ROUTE] = options => { - var pagingSpec = ReadPagingResourceFromRequest(); - if ((pagingSpec.Page == 0 && pagingSpec.PageSize == 0) || pagingSpec.PageSize == -1) - { - var all = GetResourceAll(); - return all.AsResponse(); - } - var resource = GetResourcePaged(pagingSpec); + var resource = GetResourcePaged(ReadPagingResourceFromRequest()); return resource.AsResponse(); }; } @@ -220,22 +224,26 @@ namespace NzbDrone.Api.REST private PagingResource ReadPagingResourceFromRequest() { int pageSize; - int.TryParse(Request.Query.PageSize.ToString(), out pageSize); + int.TryParse(Request.Query.PageSize.ToString(), out pageSize); + if (pageSize == 0) pageSize = 10; int page; int.TryParse(Request.Query.Page.ToString(), out page); + if (page == 0) page = 1; var pagingResource = new PagingResource { PageSize = pageSize, Page = page, + Filters = new List() }; if (Request.Query.SortKey != null) { pagingResource.SortKey = Request.Query.SortKey.ToString(); + // For backwards compatibility with v2 if (Request.Query.SortDir != null) { pagingResource.SortDirection = Request.Query.SortDir.ToString() @@ -243,24 +251,48 @@ namespace NzbDrone.Api.REST ? SortDirection.Ascending : SortDirection.Descending; } + + // v3 uses SortDirection instead of SortDir to be consistent with every other use of it + if (Request.Query.SortDirection != null) + { + pagingResource.SortDirection = Request.Query.SortDirection.ToString() + .Equals("ascending", StringComparison.InvariantCultureIgnoreCase) + ? SortDirection.Ascending + : SortDirection.Descending; + } } + // For backwards compatibility with v2 if (Request.Query.FilterKey != null) { - pagingResource.FilterKey = Request.Query.FilterKey.ToString(); + var filter = new PagingResourceFilter + { + Key = Request.Query.FilterKey.ToString() + }; if (Request.Query.FilterValue != null) { - pagingResource.FilterValue = Request.Query.FilterValue.ToString(); + filter.Value = Request.Query.FilterValue?.ToString(); } - if (Request.Query.FilterType != null) - { - pagingResource.FilterType = Request.Query.FilterType.ToString(); - } + pagingResource.Filters.Add(filter); } + // v3 uses filters in key=value format + foreach (var key in Request.Query) + { + if (EXCLUDED_KEYS.Contains(key)) + { + continue; + } + + pagingResource.Filters.Add(new PagingResourceFilter + { + Key = key, + Value = Request.Query[key] + }); + } return pagingResource; } diff --git a/src/NzbDrone.Api/REST/RestResource.cs b/src/Radarr.Http/REST/RestResource.cs similarity index 91% rename from src/NzbDrone.Api/REST/RestResource.cs rename to src/Radarr.Http/REST/RestResource.cs index ec9f195c6..2742926af 100644 --- a/src/NzbDrone.Api/REST/RestResource.cs +++ b/src/Radarr.Http/REST/RestResource.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace NzbDrone.Api.REST +namespace Radarr.Http.REST { public abstract class RestResource { diff --git a/src/Radarr.Http/REST/UnsupportedMediaTypeException.cs b/src/Radarr.Http/REST/UnsupportedMediaTypeException.cs new file mode 100644 index 000000000..be6b7d34b --- /dev/null +++ b/src/Radarr.Http/REST/UnsupportedMediaTypeException.cs @@ -0,0 +1,13 @@ +using Nancy; +using Radarr.Http.Exceptions; + +namespace Radarr.Http.REST +{ + public class UnsupportedMediaTypeException : ApiException + { + public UnsupportedMediaTypeException(object content = null) + : base(HttpStatusCode.UnsupportedMediaType, content) + { + } + } +} diff --git a/src/Radarr.Http/Radarr.Http.csproj b/src/Radarr.Http/Radarr.Http.csproj new file mode 100644 index 000000000..fc49849d2 --- /dev/null +++ b/src/Radarr.Http/Radarr.Http.csproj @@ -0,0 +1,154 @@ + + + + + Debug + AnyCPU + {C5953DAB-89DB-46D9-A401-D620F54B776E} + Library + Properties + Radarr.Http + Radarr.Http + v4.6.1 + 512 + + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + 4 + MinimumRecommendedRules.ruleset + false + MinimumRecommendedRules.ruleset + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + 4 + MinimumRecommendedRules.ruleset + false + MinimumRecommendedRules.ruleset + + + + ..\packages\FluentValidation.6.2.1.0\lib\Net45\FluentValidation.dll + + + ..\packages\Nancy.1.4.4\lib\net40\Nancy.dll + + + ..\packages\Nancy.Authentication.Basic.1.4.1\lib\net40\Nancy.Authentication.Basic.dll + + + ..\packages\Nancy.Authentication.Forms.1.4.1\lib\net40\Nancy.Authentication.Forms.dll + + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\packages\NLog.4.5.0-rc06\lib\net45\NLog.dll + + + + + ..\Libraries\Sqlite\System.Data.SQLite.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {f2be0fdf-6e47-4827-a420-dd4ef82407f8} + NzbDrone.Common + + + {ff5ee3b6-913b-47ce-9ceb-11c51b4e1205} + NzbDrone.Core + + + {7c2cc69f-5ca0-4e5c-85cb-983f9f6c3b36} + NzbDrone.SignalR + + + + + + + + \ No newline at end of file diff --git a/src/NzbDrone.Api/NancyBootstrapper.cs b/src/Radarr.Http/RadarrBootstrapper.cs similarity index 87% rename from src/NzbDrone.Api/NancyBootstrapper.cs rename to src/Radarr.Http/RadarrBootstrapper.cs index 4ac5fa6c1..5e518f894 100644 --- a/src/NzbDrone.Api/NancyBootstrapper.cs +++ b/src/Radarr.Http/RadarrBootstrapper.cs @@ -2,22 +2,22 @@ using System.Linq; using Nancy.Bootstrapper; using Nancy.Diagnostics; using NLog; -using NzbDrone.Api.Extensions.Pipelines; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Instrumentation; using NzbDrone.Core.Instrumentation; using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Messaging.Events; +using Radarr.Http.Extensions.Pipelines; using TinyIoC; -namespace NzbDrone.Api +namespace Radarr.Http { - public class NancyBootstrapper : TinyIoCNancyBootstrapper + public class RadarrBootstrapper : TinyIoCNancyBootstrapper { private readonly TinyIoCContainer _tinyIoCContainer; - private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(NancyBootstrapper)); + private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(RadarrBootstrapper)); - public NancyBootstrapper(TinyIoCContainer tinyIoCContainer) + public RadarrBootstrapper(TinyIoCContainer tinyIoCContainer) { _tinyIoCContainer = tinyIoCContainer; } diff --git a/src/NzbDrone.Api/NzbDroneRestModule.cs b/src/Radarr.Http/RadarrRestModule.cs similarity index 54% rename from src/NzbDrone.Api/NzbDroneRestModule.cs rename to src/Radarr.Http/RadarrRestModule.cs index 4cc103d95..2a73f834d 100644 --- a/src/NzbDrone.Api/NzbDroneRestModule.cs +++ b/src/Radarr.Http/RadarrRestModule.cs @@ -1,21 +1,37 @@ -using System; -using NzbDrone.Api.REST; -using NzbDrone.Api.Validation; +using System; using NzbDrone.Core.Datastore; +using Radarr.Http.REST; +using Radarr.Http.Validation; -namespace NzbDrone.Api +namespace Radarr.Http { - public abstract class NzbDroneRestModule : RestModule where TResource : RestResource, new() + public abstract class RadarrRestModule : RestModule where TResource : RestResource, new() { protected string Resource { get; private set; } - protected NzbDroneRestModule() - : this(new TResource().ResourceName) + + private static string BaseUrl() + { + var isV3 = typeof(TResource).Namespace.Contains(".V2."); + if (isV3) + { + return "/api/v2/"; + } + return "/api/"; + } + + private static string ResourceName() + { + return new TResource().ResourceName.Trim('/').ToLower(); + } + + protected RadarrRestModule() + : this(ResourceName()) { } - protected NzbDroneRestModule(string resource) - : base("/api/" + resource.Trim('/')) + protected RadarrRestModule(string resource) + : base(BaseUrl() + resource.Trim('/').ToLower()) { Resource = resource; PostValidator.RuleFor(r => r.Id).IsZero(); @@ -37,4 +53,4 @@ namespace NzbDrone.Api }; } } -} \ No newline at end of file +} diff --git a/src/Radarr.Http/RadarrRestModuleWithSignalR.cs b/src/Radarr.Http/RadarrRestModuleWithSignalR.cs new file mode 100644 index 000000000..582e9a5dc --- /dev/null +++ b/src/Radarr.Http/RadarrRestModuleWithSignalR.cs @@ -0,0 +1,79 @@ +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Datastore.Events; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.SignalR; +using Radarr.Http.REST; + +namespace Radarr.Http +{ + public abstract class RadarrRestModuleWithSignalR : RadarrRestModule, IHandle> + where TResource : RestResource, new() + where TModel : ModelBase, new() + { + private readonly IBroadcastSignalRMessage _signalRBroadcaster; + + protected RadarrRestModuleWithSignalR(IBroadcastSignalRMessage signalRBroadcaster) + { + _signalRBroadcaster = signalRBroadcaster; + } + + protected RadarrRestModuleWithSignalR(IBroadcastSignalRMessage signalRBroadcaster, string resource) + : base(resource) + { + _signalRBroadcaster = signalRBroadcaster; + } + + public void Handle(ModelEvent message) + { + if (message.Action == ModelAction.Deleted || message.Action == ModelAction.Sync) + { + BroadcastResourceChange(message.Action); + } + + BroadcastResourceChange(message.Action, message.Model.Id); + } + + protected void BroadcastResourceChange(ModelAction action, int id) + { + if (action == ModelAction.Deleted) + { + BroadcastResourceChange(action, new TResource {Id = id}); + } + else + { + var resource = GetResourceById(id); + BroadcastResourceChange(action, resource); + } + } + + protected void BroadcastResourceChange(ModelAction action, TResource resource) + { + if (GetType().Namespace.Contains("V2")) + { + var signalRMessage = new SignalRMessage + { + Name = Resource, + Body = new ResourceChangeMessage(resource, action), + Action = action + }; + + _signalRBroadcaster.BroadcastMessage(signalRMessage); + } + } + + protected void BroadcastResourceChange(ModelAction action) + { + if (GetType().Namespace.Contains("V2")) + { + var signalRMessage = new SignalRMessage + { + Name = Resource, + Body = new ResourceChangeMessage(action), + Action = action + }; + + _signalRBroadcaster.BroadcastMessage(signalRMessage); + } + } + } +} diff --git a/src/NzbDrone.Api/ResourceChangeMessage.cs b/src/Radarr.Http/ResourceChangeMessage.cs similarity index 93% rename from src/NzbDrone.Api/ResourceChangeMessage.cs rename to src/Radarr.Http/ResourceChangeMessage.cs index 6319dcc39..26ca6605f 100644 --- a/src/NzbDrone.Api/ResourceChangeMessage.cs +++ b/src/Radarr.Http/ResourceChangeMessage.cs @@ -1,8 +1,8 @@ using System; -using NzbDrone.Api.REST; using NzbDrone.Core.Datastore.Events; +using Radarr.Http.REST; -namespace NzbDrone.Api +namespace Radarr.Http { public class ResourceChangeMessage where TResource : RestResource { diff --git a/src/NzbDrone.Api/TinyIoCNancyBootstrapper.cs b/src/Radarr.Http/TinyIoCNancyBootstrapper.cs similarity index 99% rename from src/NzbDrone.Api/TinyIoCNancyBootstrapper.cs rename to src/Radarr.Http/TinyIoCNancyBootstrapper.cs index 5be766761..d713eb8db 100644 --- a/src/NzbDrone.Api/TinyIoCNancyBootstrapper.cs +++ b/src/Radarr.Http/TinyIoCNancyBootstrapper.cs @@ -7,7 +7,7 @@ using Nancy; using Nancy.Diagnostics; using Nancy.Bootstrapper; -namespace NzbDrone.Api +namespace Radarr.Http { @@ -22,7 +22,7 @@ namespace NzbDrone.Api /// public static IEnumerable> DefaultAutoRegisterIgnoredAssemblies = new Func[] { - asm => !asm.FullName.StartsWith("Nancy.", StringComparison.InvariantCulture), + asm => !asm.FullName.StartsWith("Nancy.", StringComparison.InvariantCulture) }; /// diff --git a/src/NzbDrone.Api/Validation/EmptyCollectionValidator.cs b/src/Radarr.Http/Validation/EmptyCollectionValidator.cs similarity index 94% rename from src/NzbDrone.Api/Validation/EmptyCollectionValidator.cs rename to src/Radarr.Http/Validation/EmptyCollectionValidator.cs index 432eb1ed9..1ebd9ed51 100644 --- a/src/NzbDrone.Api/Validation/EmptyCollectionValidator.cs +++ b/src/Radarr.Http/Validation/EmptyCollectionValidator.cs @@ -2,7 +2,7 @@ using FluentValidation.Validators; using NzbDrone.Common.Extensions; -namespace NzbDrone.Api.Validation +namespace Radarr.Http.Validation { public class EmptyCollectionValidator : PropertyValidator { diff --git a/src/NzbDrone.Api/Validation/NetImportSyncIntervalValidator.cs b/src/Radarr.Http/Validation/NetImportSyncIntervalValidator.cs similarity index 90% rename from src/NzbDrone.Api/Validation/NetImportSyncIntervalValidator.cs rename to src/Radarr.Http/Validation/NetImportSyncIntervalValidator.cs index b44b3f9e4..5593e4a98 100644 --- a/src/NzbDrone.Api/Validation/NetImportSyncIntervalValidator.cs +++ b/src/Radarr.Http/Validation/NetImportSyncIntervalValidator.cs @@ -1,6 +1,6 @@ -using FluentValidation.Validators; +using FluentValidation.Validators; -namespace NzbDrone.Api.Validation +namespace Radarr.Http.Validation { public class NetImportSyncIntervalValidator : PropertyValidator { diff --git a/src/NzbDrone.Api/Validation/RssSyncIntervalValidator.cs b/src/Radarr.Http/Validation/RssSyncIntervalValidator.cs similarity index 80% rename from src/NzbDrone.Api/Validation/RssSyncIntervalValidator.cs rename to src/Radarr.Http/Validation/RssSyncIntervalValidator.cs index fce86cd86..76063ce28 100644 --- a/src/NzbDrone.Api/Validation/RssSyncIntervalValidator.cs +++ b/src/Radarr.Http/Validation/RssSyncIntervalValidator.cs @@ -1,11 +1,11 @@ using FluentValidation.Validators; -namespace NzbDrone.Api.Validation +namespace Radarr.Http.Validation { public class RssSyncIntervalValidator : PropertyValidator { public RssSyncIntervalValidator() - : base("Must be between 10 and 720 or 0 to disable") + : base("Must be between 10 and 120 or 0 to disable") { } @@ -23,7 +23,7 @@ namespace NzbDrone.Api.Validation return true; } - if (value >= 10 && value <= 720) + if (value >= 10 && value <= 120) { return true; } diff --git a/src/NzbDrone.Api/Validation/RuleBuilderExtensions.cs b/src/Radarr.Http/Validation/RuleBuilderExtensions.cs similarity index 83% rename from src/NzbDrone.Api/Validation/RuleBuilderExtensions.cs rename to src/Radarr.Http/Validation/RuleBuilderExtensions.cs index c60be7fd0..dcaeb8bf1 100644 --- a/src/NzbDrone.Api/Validation/RuleBuilderExtensions.cs +++ b/src/Radarr.Http/Validation/RuleBuilderExtensions.cs @@ -1,10 +1,9 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Text.RegularExpressions; using FluentValidation; using FluentValidation.Validators; -using NzbDrone.Api.Qualities; -namespace NzbDrone.Api.Validation +namespace Radarr.Http.Validation { public static class RuleBuilderExtensions { @@ -42,11 +41,5 @@ namespace NzbDrone.Api.Validation { return ruleBuilder.SetValidator(new NetImportSyncIntervalValidator()); } - - public static IRuleBuilderOptions> AreValidFormatTags( - this IRuleBuilder> ruleBuilder) - { - return ruleBuilder.SetValidator(new FormatTagValidator()); - } } } diff --git a/src/Radarr.Http/app.config b/src/Radarr.Http/app.config new file mode 100644 index 000000000..0c4e911c9 --- /dev/null +++ b/src/Radarr.Http/app.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Radarr.Http/packages.config b/src/Radarr.Http/packages.config new file mode 100644 index 000000000..eebacd203 --- /dev/null +++ b/src/Radarr.Http/packages.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/Radarr.sln b/src/Radarr.sln new file mode 100644 index 000000000..1e5e7321c --- /dev/null +++ b/src/Radarr.sln @@ -0,0 +1,328 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2010 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Console", "NzbDrone.Console\NzbDrone.Console.csproj", "{3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}" + ProjectSection(ProjectDependencies) = postProject + {15AD7579-A314-4626-B556-663F51D97CD1} = {15AD7579-A314-4626-B556-663F51D97CD1} + {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36} = {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36} + {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205} = {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205} + {911284D3-F130-459E-836C-2430B6FBF21D} = {911284D3-F130-459E-836C-2430B6FBF21D} + {FD286DF8-2D3A-4394-8AD5-443FADE55FB2} = {FD286DF8-2D3A-4394-8AD5-443FADE55FB2} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{57A04B72-8088-4F75-A582-1158CF8291F7}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test.Common", "Test.Common", "{47697CDB-27B6-4B05-B4F8-0CBE6F6EDF97}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Test.Dummy", "NzbDrone.Test.Dummy\NzbDrone.Test.Dummy.csproj", "{FAFB5948-A222-4CF6-AD14-026BE7564802}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Test.Common", "NzbDrone.Test.Common\NzbDrone.Test.Common.csproj", "{CADDFCE0-7509-4430-8364-2074E1EEFCA2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Core.Test", "NzbDrone.Core.Test\NzbDrone.Core.Test.csproj", "{193ADD3B-792B-4173-8E4C-5A3F8F0237F0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Host.Test", "NzbDrone.App.Test\NzbDrone.Host.Test.csproj", "{C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Update.Test", "NzbDrone.Update.Test\NzbDrone.Update.Test.csproj", "{35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Common.Test", "NzbDrone.Common.Test\NzbDrone.Common.Test.csproj", "{BEC74619-DDBB-4FBA-B517-D3E20AFC9997}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Api.Test", "NzbDrone.Api.Test\NzbDrone.Api.Test.csproj", "{D18A5DEB-5102-4775-A1AF-B75DAAA8907B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Libraries.Test", "NzbDrone.Libraries.Test\NzbDrone.Libraries.Test.csproj", "{CBF6B8B0-A015-413A-8C86-01238BB45770}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Integration.Test", "NzbDrone.Integration.Test\NzbDrone.Integration.Test.csproj", "{8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Automation.Test", "NzbDrone.Automation.Test\NzbDrone.Automation.Test.csproj", "{CC26800D-F67E-464B-88DE-8EB1A0C227A3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WindowsServiceHelpers", "WindowsServiceHelpers", "{F9E67978-5CD6-4A5F-827B-4249711C0B02}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceInstall", "ServiceHelpers\ServiceInstall\ServiceInstall.csproj", "{6BCE712F-846D-4846-9D1B-A66B858DA755}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceUninstall", "ServiceHelpers\ServiceUninstall\ServiceUninstall.csproj", "{700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Core", "NzbDrone.Core\NzbDrone.Core.csproj", "{FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Update", "NzbDrone.Update\NzbDrone.Update.csproj", "{4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Common", "NzbDrone.Common\NzbDrone.Common.csproj", "{F2BE0FDF-6E47-4827-A420-DD4EF82407F8}" + ProjectSection(ProjectDependencies) = postProject + {9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB} = {9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1E6B3CBE-1578-41C1-9BF9-78D818740BE9}" + ProjectSection(SolutionItems) = preProject + .nuget\NuGet.exe = .nuget\NuGet.exe + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Api", "NzbDrone.Api\NzbDrone.Api.csproj", "{FD286DF8-2D3A-4394-8AD5-443FADE55FB2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Host", "Host", "{486ADF86-DD89-4E19-B805-9D94F19800D9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Host", "NzbDrone.Host\NzbDrone.Host.csproj", "{95C11A9E-56ED-456A-8447-2C89C1139266}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone", "NzbDrone\NzbDrone.csproj", "{D12F7F2F-8A3C-415F-88FA-6DD061A84869}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.SignalR", "NzbDrone.SignalR\NzbDrone.SignalR.csproj", "{7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "External", "External", "{F6E3A728-AE77-4D02-BAC8-82FBC1402DDA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marr.Data", "Marr.Data\Marr.Data.csproj", "{F6FC6BE7-0847-4817-A1ED-223DC647C3D7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Mono", "NzbDrone.Mono\NzbDrone.Mono.csproj", "{15AD7579-A314-4626-B556-663F51D97CD1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Windows", "NzbDrone.Windows\NzbDrone.Windows.csproj", "{911284D3-F130-459E-836C-2430B6FBF21D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Platform", "Platform", "{0F0D4998-8F5D-4467-A909-BB192C4B3B4B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Platform", "Platform", "{4EACDBBC-BCD7-4765-A57B-3E08331E4749}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Windows.Test", "NzbDrone.Windows.Test\NzbDrone.Windows.Test.csproj", "{80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Mono.Test", "NzbDrone.Mono.Test\NzbDrone.Mono.Test.csproj", "{40D72824-7D02-4A77-9106-8FE0EEA2B997}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoTorrent", "MonoTorrent\MonoTorrent.csproj", "{411A9E0E-FDC6-4E25-828A-0C2CD1CD96F8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogentriesCore", "LogentriesCore\LogentriesCore.csproj", "{90D6E9FC-7B88-4E1B-B018-8FA742274558}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogentriesNLog", "LogentriesNLog\LogentriesNLog.csproj", "{9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB}" + ProjectSection(ProjectDependencies) = postProject + {90D6E9FC-7B88-4E1B-B018-8FA742274558} = {90D6E9FC-7B88-4E1B-B018-8FA742274558} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CurlSharp", "ExternalModules\CurlSharp\CurlSharp\CurlSharp.csproj", "{74420A79-CC16-442C-8B1E-7C1B913844F0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Radarr.Http", "Radarr.Http\Radarr.Http.csproj", "{C5953DAB-89DB-46D9-A401-D620F54B776E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Radarr.Api.V2", "Radarr.Api.V2\Radarr.Api.V2.csproj", "{38497DC6-E488-4B9E-A973-A1A7961B33C4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Mono|x86 = Mono|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Debug|x86.ActiveCfg = Debug|x86 + {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Debug|x86.Build.0 = Debug|x86 + {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Mono|x86.ActiveCfg = Debug|x86 + {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Mono|x86.Build.0 = Debug|x86 + {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Release|x86.ActiveCfg = Release|x86 + {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Release|x86.Build.0 = Release|x86 + {FAFB5948-A222-4CF6-AD14-026BE7564802}.Debug|x86.ActiveCfg = Debug|x86 + {FAFB5948-A222-4CF6-AD14-026BE7564802}.Debug|x86.Build.0 = Debug|x86 + {FAFB5948-A222-4CF6-AD14-026BE7564802}.Mono|x86.ActiveCfg = Release|x86 + {FAFB5948-A222-4CF6-AD14-026BE7564802}.Mono|x86.Build.0 = Release|x86 + {FAFB5948-A222-4CF6-AD14-026BE7564802}.Release|x86.ActiveCfg = Release|x86 + {FAFB5948-A222-4CF6-AD14-026BE7564802}.Release|x86.Build.0 = Release|x86 + {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Debug|x86.ActiveCfg = Debug|x86 + {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Debug|x86.Build.0 = Debug|x86 + {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Mono|x86.ActiveCfg = Debug|x86 + {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Mono|x86.Build.0 = Debug|x86 + {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Release|x86.ActiveCfg = Release|x86 + {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Release|x86.Build.0 = Release|x86 + {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Debug|x86.ActiveCfg = Debug|x86 + {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Debug|x86.Build.0 = Debug|x86 + {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Mono|x86.ActiveCfg = Debug|x86 + {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Mono|x86.Build.0 = Debug|x86 + {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Release|x86.ActiveCfg = Release|x86 + {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Release|x86.Build.0 = Release|x86 + {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Debug|x86.ActiveCfg = Debug|x86 + {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Debug|x86.Build.0 = Debug|x86 + {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Mono|x86.ActiveCfg = Debug|x86 + {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Mono|x86.Build.0 = Debug|x86 + {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Release|x86.ActiveCfg = Release|x86 + {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Release|x86.Build.0 = Release|x86 + {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Debug|x86.ActiveCfg = Debug|x86 + {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Debug|x86.Build.0 = Debug|x86 + {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Mono|x86.ActiveCfg = Debug|x86 + {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Mono|x86.Build.0 = Debug|x86 + {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Release|x86.ActiveCfg = Release|x86 + {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Release|x86.Build.0 = Release|x86 + {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Debug|x86.ActiveCfg = Debug|x86 + {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Debug|x86.Build.0 = Debug|x86 + {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Mono|x86.ActiveCfg = Debug|x86 + {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Mono|x86.Build.0 = Debug|x86 + {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Release|x86.ActiveCfg = Release|x86 + {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Release|x86.Build.0 = Release|x86 + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Debug|x86.ActiveCfg = Debug|x86 + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Debug|x86.Build.0 = Debug|x86 + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Mono|x86.ActiveCfg = Release|x86 + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Mono|x86.Build.0 = Release|x86 + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Release|x86.ActiveCfg = Release|x86 + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Release|x86.Build.0 = Release|x86 + {CBF6B8B0-A015-413A-8C86-01238BB45770}.Debug|x86.ActiveCfg = Debug|x86 + {CBF6B8B0-A015-413A-8C86-01238BB45770}.Debug|x86.Build.0 = Debug|x86 + {CBF6B8B0-A015-413A-8C86-01238BB45770}.Mono|x86.ActiveCfg = Debug|x86 + {CBF6B8B0-A015-413A-8C86-01238BB45770}.Mono|x86.Build.0 = Debug|x86 + {CBF6B8B0-A015-413A-8C86-01238BB45770}.Release|x86.ActiveCfg = Release|x86 + {CBF6B8B0-A015-413A-8C86-01238BB45770}.Release|x86.Build.0 = Release|x86 + {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Debug|x86.ActiveCfg = Debug|x86 + {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Debug|x86.Build.0 = Debug|x86 + {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Mono|x86.ActiveCfg = Debug|x86 + {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Mono|x86.Build.0 = Debug|x86 + {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Release|x86.ActiveCfg = Release|x86 + {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Release|x86.Build.0 = Release|x86 + {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Debug|x86.ActiveCfg = Debug|x86 + {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Debug|x86.Build.0 = Debug|x86 + {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Mono|x86.ActiveCfg = Debug|x86 + {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Mono|x86.Build.0 = Debug|x86 + {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Release|x86.ActiveCfg = Release|x86 + {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Release|x86.Build.0 = Release|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Debug|x86.ActiveCfg = Debug|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Debug|x86.Build.0 = Debug|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Mono|x86.ActiveCfg = Debug|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Release|x86.ActiveCfg = Release|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Release|x86.Build.0 = Release|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Debug|x86.ActiveCfg = Debug|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Debug|x86.Build.0 = Debug|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Mono|x86.ActiveCfg = Debug|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Release|x86.ActiveCfg = Release|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Release|x86.Build.0 = Release|x86 + {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Debug|x86.ActiveCfg = Debug|x86 + {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Debug|x86.Build.0 = Debug|x86 + {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Mono|x86.ActiveCfg = Release|x86 + {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Mono|x86.Build.0 = Release|x86 + {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Release|x86.ActiveCfg = Release|x86 + {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Release|x86.Build.0 = Release|x86 + {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Debug|x86.ActiveCfg = Debug|x86 + {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Debug|x86.Build.0 = Debug|x86 + {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Mono|x86.ActiveCfg = Debug|x86 + {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Mono|x86.Build.0 = Debug|x86 + {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Release|x86.ActiveCfg = Release|x86 + {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Release|x86.Build.0 = Release|x86 + {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Debug|x86.ActiveCfg = Debug|x86 + {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Debug|x86.Build.0 = Debug|x86 + {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Mono|x86.ActiveCfg = Release|x86 + {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Mono|x86.Build.0 = Release|x86 + {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Release|x86.ActiveCfg = Release|x86 + {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Release|x86.Build.0 = Release|x86 + {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Debug|x86.ActiveCfg = Debug|x86 + {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Debug|x86.Build.0 = Debug|x86 + {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Mono|x86.ActiveCfg = Release|x86 + {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Mono|x86.Build.0 = Release|x86 + {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Release|x86.ActiveCfg = Release|x86 + {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Release|x86.Build.0 = Release|x86 + {95C11A9E-56ED-456A-8447-2C89C1139266}.Debug|x86.ActiveCfg = Debug|x86 + {95C11A9E-56ED-456A-8447-2C89C1139266}.Debug|x86.Build.0 = Debug|x86 + {95C11A9E-56ED-456A-8447-2C89C1139266}.Mono|x86.ActiveCfg = Debug|x86 + {95C11A9E-56ED-456A-8447-2C89C1139266}.Mono|x86.Build.0 = Debug|x86 + {95C11A9E-56ED-456A-8447-2C89C1139266}.Release|x86.ActiveCfg = Release|x86 + {95C11A9E-56ED-456A-8447-2C89C1139266}.Release|x86.Build.0 = Release|x86 + {D12F7F2F-8A3C-415F-88FA-6DD061A84869}.Debug|x86.ActiveCfg = Debug|x86 + {D12F7F2F-8A3C-415F-88FA-6DD061A84869}.Debug|x86.Build.0 = Debug|x86 + {D12F7F2F-8A3C-415F-88FA-6DD061A84869}.Mono|x86.ActiveCfg = Release|x86 + {D12F7F2F-8A3C-415F-88FA-6DD061A84869}.Release|x86.ActiveCfg = Release|x86 + {D12F7F2F-8A3C-415F-88FA-6DD061A84869}.Release|x86.Build.0 = Release|x86 + {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Debug|x86.ActiveCfg = Debug|x86 + {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Debug|x86.Build.0 = Debug|x86 + {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Mono|x86.ActiveCfg = Debug|x86 + {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Mono|x86.Build.0 = Debug|x86 + {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Release|x86.ActiveCfg = Release|x86 + {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Release|x86.Build.0 = Release|x86 + {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Debug|x86.ActiveCfg = Debug|x86 + {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Debug|x86.Build.0 = Debug|x86 + {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Mono|x86.ActiveCfg = Release|x86 + {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Mono|x86.Build.0 = Release|x86 + {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Release|x86.ActiveCfg = Release|x86 + {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Release|x86.Build.0 = Release|x86 + {15AD7579-A314-4626-B556-663F51D97CD1}.Debug|x86.ActiveCfg = Debug|x86 + {15AD7579-A314-4626-B556-663F51D97CD1}.Debug|x86.Build.0 = Debug|x86 + {15AD7579-A314-4626-B556-663F51D97CD1}.Mono|x86.ActiveCfg = Release|x86 + {15AD7579-A314-4626-B556-663F51D97CD1}.Release|x86.ActiveCfg = Release|x86 + {15AD7579-A314-4626-B556-663F51D97CD1}.Release|x86.Build.0 = Release|x86 + {911284D3-F130-459E-836C-2430B6FBF21D}.Debug|x86.ActiveCfg = Debug|x86 + {911284D3-F130-459E-836C-2430B6FBF21D}.Debug|x86.Build.0 = Debug|x86 + {911284D3-F130-459E-836C-2430B6FBF21D}.Mono|x86.ActiveCfg = Release|x86 + {911284D3-F130-459E-836C-2430B6FBF21D}.Release|x86.ActiveCfg = Release|x86 + {911284D3-F130-459E-836C-2430B6FBF21D}.Release|x86.Build.0 = Release|x86 + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Debug|x86.ActiveCfg = Debug|x86 + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Debug|x86.Build.0 = Debug|x86 + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Mono|x86.ActiveCfg = Release|x86 + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Release|x86.ActiveCfg = Release|x86 + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Release|x86.Build.0 = Release|x86 + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Debug|x86.ActiveCfg = Debug|x86 + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Debug|x86.Build.0 = Debug|x86 + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Mono|x86.ActiveCfg = Release|x86 + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Release|x86.ActiveCfg = Release|x86 + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Release|x86.Build.0 = Release|x86 + {411A9E0E-FDC6-4E25-828A-0C2CD1CD96F8}.Debug|x86.ActiveCfg = Debug|x86 + {411A9E0E-FDC6-4E25-828A-0C2CD1CD96F8}.Debug|x86.Build.0 = Debug|x86 + {411A9E0E-FDC6-4E25-828A-0C2CD1CD96F8}.Mono|x86.ActiveCfg = Release|x86 + {411A9E0E-FDC6-4E25-828A-0C2CD1CD96F8}.Mono|x86.Build.0 = Release|x86 + {411A9E0E-FDC6-4E25-828A-0C2CD1CD96F8}.Release|x86.ActiveCfg = Release|x86 + {411A9E0E-FDC6-4E25-828A-0C2CD1CD96F8}.Release|x86.Build.0 = Release|x86 + {90D6E9FC-7B88-4E1B-B018-8FA742274558}.Debug|x86.ActiveCfg = Debug|x86 + {90D6E9FC-7B88-4E1B-B018-8FA742274558}.Debug|x86.Build.0 = Debug|x86 + {90D6E9FC-7B88-4E1B-B018-8FA742274558}.Mono|x86.ActiveCfg = Release|x86 + {90D6E9FC-7B88-4E1B-B018-8FA742274558}.Mono|x86.Build.0 = Release|x86 + {90D6E9FC-7B88-4E1B-B018-8FA742274558}.Release|x86.ActiveCfg = Release|x86 + {90D6E9FC-7B88-4E1B-B018-8FA742274558}.Release|x86.Build.0 = Release|x86 + {9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB}.Debug|x86.ActiveCfg = Debug|x86 + {9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB}.Debug|x86.Build.0 = Debug|x86 + {9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB}.Mono|x86.ActiveCfg = Release|x86 + {9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB}.Mono|x86.Build.0 = Release|x86 + {9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB}.Release|x86.ActiveCfg = Release|x86 + {9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB}.Release|x86.Build.0 = Release|x86 + {74420A79-CC16-442C-8B1E-7C1B913844F0}.Debug|x86.ActiveCfg = Debug|Any CPU + {74420A79-CC16-442C-8B1E-7C1B913844F0}.Debug|x86.Build.0 = Debug|Any CPU + {74420A79-CC16-442C-8B1E-7C1B913844F0}.Mono|x86.ActiveCfg = Release|Any CPU + {74420A79-CC16-442C-8B1E-7C1B913844F0}.Mono|x86.Build.0 = Release|Any CPU + {74420A79-CC16-442C-8B1E-7C1B913844F0}.Release|x86.ActiveCfg = Release|Any CPU + {74420A79-CC16-442C-8B1E-7C1B913844F0}.Release|x86.Build.0 = Release|Any CPU + {C5953DAB-89DB-46D9-A401-D620F54B776E}.Debug|x86.ActiveCfg = Debug|x86 + {C5953DAB-89DB-46D9-A401-D620F54B776E}.Debug|x86.Build.0 = Debug|x86 + {C5953DAB-89DB-46D9-A401-D620F54B776E}.Mono|x86.ActiveCfg = Release|x86 + {C5953DAB-89DB-46D9-A401-D620F54B776E}.Mono|x86.Build.0 = Release|x86 + {C5953DAB-89DB-46D9-A401-D620F54B776E}.Release|x86.ActiveCfg = Release|x86 + {C5953DAB-89DB-46D9-A401-D620F54B776E}.Release|x86.Build.0 = Release|x86 + {38497DC6-E488-4B9E-A973-A1A7961B33C4}.Debug|x86.ActiveCfg = Debug|x86 + {38497DC6-E488-4B9E-A973-A1A7961B33C4}.Debug|x86.Build.0 = Debug|x86 + {38497DC6-E488-4B9E-A973-A1A7961B33C4}.Mono|x86.ActiveCfg = Release|x86 + {38497DC6-E488-4B9E-A973-A1A7961B33C4}.Mono|x86.Build.0 = Release|x86 + {38497DC6-E488-4B9E-A973-A1A7961B33C4}.Release|x86.ActiveCfg = Release|x86 + {38497DC6-E488-4B9E-A973-A1A7961B33C4}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976} = {486ADF86-DD89-4E19-B805-9D94F19800D9} + {47697CDB-27B6-4B05-B4F8-0CBE6F6EDF97} = {57A04B72-8088-4F75-A582-1158CF8291F7} + {FAFB5948-A222-4CF6-AD14-026BE7564802} = {47697CDB-27B6-4B05-B4F8-0CBE6F6EDF97} + {CADDFCE0-7509-4430-8364-2074E1EEFCA2} = {47697CDB-27B6-4B05-B4F8-0CBE6F6EDF97} + {193ADD3B-792B-4173-8E4C-5A3F8F0237F0} = {57A04B72-8088-4F75-A582-1158CF8291F7} + {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5} = {57A04B72-8088-4F75-A582-1158CF8291F7} + {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97} = {57A04B72-8088-4F75-A582-1158CF8291F7} + {BEC74619-DDBB-4FBA-B517-D3E20AFC9997} = {57A04B72-8088-4F75-A582-1158CF8291F7} + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B} = {57A04B72-8088-4F75-A582-1158CF8291F7} + {CBF6B8B0-A015-413A-8C86-01238BB45770} = {57A04B72-8088-4F75-A582-1158CF8291F7} + {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB} = {57A04B72-8088-4F75-A582-1158CF8291F7} + {CC26800D-F67E-464B-88DE-8EB1A0C227A3} = {57A04B72-8088-4F75-A582-1158CF8291F7} + {6BCE712F-846D-4846-9D1B-A66B858DA755} = {F9E67978-5CD6-4A5F-827B-4249711C0B02} + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4} = {F9E67978-5CD6-4A5F-827B-4249711C0B02} + {95C11A9E-56ED-456A-8447-2C89C1139266} = {486ADF86-DD89-4E19-B805-9D94F19800D9} + {D12F7F2F-8A3C-415F-88FA-6DD061A84869} = {486ADF86-DD89-4E19-B805-9D94F19800D9} + {F6FC6BE7-0847-4817-A1ED-223DC647C3D7} = {F6E3A728-AE77-4D02-BAC8-82FBC1402DDA} + {15AD7579-A314-4626-B556-663F51D97CD1} = {0F0D4998-8F5D-4467-A909-BB192C4B3B4B} + {911284D3-F130-459E-836C-2430B6FBF21D} = {0F0D4998-8F5D-4467-A909-BB192C4B3B4B} + {4EACDBBC-BCD7-4765-A57B-3E08331E4749} = {57A04B72-8088-4F75-A582-1158CF8291F7} + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA} = {4EACDBBC-BCD7-4765-A57B-3E08331E4749} + {40D72824-7D02-4A77-9106-8FE0EEA2B997} = {4EACDBBC-BCD7-4765-A57B-3E08331E4749} + {411A9E0E-FDC6-4E25-828A-0C2CD1CD96F8} = {F6E3A728-AE77-4D02-BAC8-82FBC1402DDA} + {90D6E9FC-7B88-4E1B-B018-8FA742274558} = {F6E3A728-AE77-4D02-BAC8-82FBC1402DDA} + {9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB} = {F6E3A728-AE77-4D02-BAC8-82FBC1402DDA} + {74420A79-CC16-442C-8B1E-7C1B913844F0} = {F6E3A728-AE77-4D02-BAC8-82FBC1402DDA} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EnterpriseLibraryConfigurationToolBinariesPath = packages\Unity.2.1.505.0\lib\NET35;packages\Unity.2.1.505.2\lib\NET35 + SolutionGuid = {2955716E-0882-41EC-935D-C95694C5C30F} + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = NzbDrone.Console\NzbDrone.Console.csproj + EndGlobalSection + GlobalSection(JSLint) = preSolution + SolutionConfigurationLocation = JSLintOptions.xml + EndGlobalSection +EndGlobal diff --git a/src/ServiceHelpers/ServiceInstall/ServiceHelper.cs b/src/ServiceHelpers/ServiceInstall/ServiceHelper.cs index 5e8880978..2b8fa682b 100644 --- a/src/ServiceHelpers/ServiceInstall/ServiceHelper.cs +++ b/src/ServiceHelpers/ServiceInstall/ServiceHelper.cs @@ -8,7 +8,7 @@ namespace ServiceInstall { public static class ServiceHelper { - private static string NzbDroneExe => Path.Combine(new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName, "Radarr.Console.exe"); + private static string RadarrExe => Path.Combine(new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName, "Radarr.Console.exe"); private static bool IsAnAdministrator() { @@ -18,7 +18,7 @@ namespace ServiceInstall public static void Run(string arg) { - if (!File.Exists(NzbDroneExe)) + if (!File.Exists(RadarrExe)) { Console.WriteLine("Unable to find Radarr.Console.exe in the current directory."); return; @@ -32,7 +32,7 @@ namespace ServiceInstall var startInfo = new ProcessStartInfo { - FileName = NzbDroneExe, + FileName = RadarrExe, Arguments = arg, UseShellExecute = false, RedirectStandardOutput = true, @@ -59,4 +59,4 @@ namespace ServiceInstall } } -} \ No newline at end of file +} diff --git a/src/ServiceHelpers/ServiceUninstall/ServiceHelper.cs b/src/ServiceHelpers/ServiceUninstall/ServiceHelper.cs index 1a046b1b3..22e08424f 100644 --- a/src/ServiceHelpers/ServiceUninstall/ServiceHelper.cs +++ b/src/ServiceHelpers/ServiceUninstall/ServiceHelper.cs @@ -8,7 +8,7 @@ namespace ServiceUninstall { public static class ServiceHelper { - private static string NzbDroneExe => Path.Combine(new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName, "Radarr.Console.exe"); + private static string RadarrExe => Path.Combine(new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName, "Radarr.Console.exe"); private static bool IsAnAdministrator() { @@ -18,7 +18,7 @@ namespace ServiceUninstall public static void Run(string arg) { - if (!File.Exists(NzbDroneExe)) + if (!File.Exists(RadarrExe)) { Console.WriteLine("Unable to find Radarr.exe in the current directory."); return; @@ -32,7 +32,7 @@ namespace ServiceUninstall var startInfo = new ProcessStartInfo { - FileName = NzbDroneExe, + FileName = RadarrExe, Arguments = arg, UseShellExecute = false, RedirectStandardOutput = true, @@ -59,4 +59,4 @@ namespace ServiceUninstall } } -} \ No newline at end of file +}