parent
0201aa812e
commit
8d64a987e0
@ -1,31 +0,0 @@
|
||||
using Nancy;
|
||||
using Lidarr.Http.Extensions;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Api.AlbumPass
|
||||
{
|
||||
public class AlbumStudioModule : NzbDroneApiModule
|
||||
{
|
||||
private readonly IAlbumMonitoredService _albumMonitoredService;
|
||||
|
||||
public AlbumStudioModule(IAlbumMonitoredService albumMonitoredService)
|
||||
: base("/albumstudio")
|
||||
{
|
||||
_albumMonitoredService = albumMonitoredService;
|
||||
Post["/"] = artist => UpdateAll();
|
||||
}
|
||||
|
||||
private Response UpdateAll()
|
||||
{
|
||||
//Read from request
|
||||
var request = Request.Body.FromJson<AlbumStudioResource>();
|
||||
|
||||
foreach (var s in request.Artist)
|
||||
{
|
||||
_albumMonitoredService.SetAlbumMonitoredStatus(s, request.MonitoringOptions);
|
||||
}
|
||||
|
||||
return "ok".AsResponse(HttpStatusCode.Accepted);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.ArtistStats;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.SignalR;
|
||||
|
||||
namespace NzbDrone.Api.Albums
|
||||
{
|
||||
public class AlbumModule : AlbumModuleWithSignalR
|
||||
{
|
||||
public AlbumModule(IArtistService artistService,
|
||||
IArtistStatisticsService artistStatisticsService,
|
||||
IAlbumService albumService,
|
||||
IUpgradableSpecification qualityUpgradableSpecification,
|
||||
IBroadcastSignalRMessage signalRBroadcaster)
|
||||
: base(albumService, artistStatisticsService, artistService, qualityUpgradableSpecification, signalRBroadcaster)
|
||||
{
|
||||
GetResourceAll = GetAlbums;
|
||||
UpdateResource = SetMonitored;
|
||||
}
|
||||
|
||||
private List<AlbumResource> GetAlbums()
|
||||
{
|
||||
if (!Request.Query.ArtistId.HasValue)
|
||||
{
|
||||
throw new BadRequestException("artistId is missing");
|
||||
}
|
||||
|
||||
var artistId = (int)Request.Query.ArtistId;
|
||||
|
||||
var resources = MapToResource(_albumService.GetAlbumsByArtist(artistId), false);
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
private void SetMonitored(AlbumResource albumResource)
|
||||
{
|
||||
_albumService.SetAlbumMonitored(albumResource.Id, albumResource.Monitored);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Api.TrackFiles;
|
||||
using NzbDrone.Api.Music;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.ArtistStats;
|
||||
using NzbDrone.SignalR;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Albums
|
||||
{
|
||||
public abstract class AlbumModuleWithSignalR : LidarrRestModuleWithSignalR<AlbumResource, Album>
|
||||
{
|
||||
protected readonly IAlbumService _albumService;
|
||||
protected readonly IArtistStatisticsService _artistStatisticsService;
|
||||
protected readonly IArtistService _artistService;
|
||||
protected readonly IUpgradableSpecification _qualityUpgradableSpecification;
|
||||
|
||||
protected AlbumModuleWithSignalR(IAlbumService albumService,
|
||||
IArtistStatisticsService artistStatisticsService,
|
||||
IArtistService artistService,
|
||||
IUpgradableSpecification qualityUpgradableSpecification,
|
||||
IBroadcastSignalRMessage signalRBroadcaster)
|
||||
: base(signalRBroadcaster)
|
||||
{
|
||||
_albumService = albumService;
|
||||
_artistStatisticsService = artistStatisticsService;
|
||||
_artistService = artistService;
|
||||
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||
|
||||
GetResourceById = GetAlbum;
|
||||
}
|
||||
|
||||
protected AlbumModuleWithSignalR(IAlbumService albumService,
|
||||
IArtistStatisticsService artistStatisticsService,
|
||||
IArtistService artistService,
|
||||
IUpgradableSpecification qualityUpgradableSpecification,
|
||||
IBroadcastSignalRMessage signalRBroadcaster,
|
||||
string resource)
|
||||
: base(signalRBroadcaster, resource)
|
||||
{
|
||||
_albumService = albumService;
|
||||
_artistStatisticsService = artistStatisticsService;
|
||||
_artistService = artistService;
|
||||
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||
|
||||
GetResourceById = GetAlbum;
|
||||
}
|
||||
|
||||
protected AlbumResource GetAlbum(int id)
|
||||
{
|
||||
var album = _albumService.GetAlbum(id);
|
||||
var resource = MapToResource(album, true);
|
||||
return resource;
|
||||
}
|
||||
|
||||
protected AlbumResource MapToResource(Album album, bool includeArtist)
|
||||
{
|
||||
var resource = album.ToResource();
|
||||
|
||||
if (includeArtist)
|
||||
{
|
||||
var artist = album.Artist ?? _artistService.GetArtist(album.ArtistId);
|
||||
|
||||
if (includeArtist)
|
||||
{
|
||||
resource.Artist = artist.ToResource();
|
||||
}
|
||||
}
|
||||
|
||||
FetchAndLinkAlbumStatistics(resource);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
protected List<AlbumResource> MapToResource(List<Album> albums, bool includeArtist)
|
||||
{
|
||||
var result = albums.ToResource();
|
||||
|
||||
if (includeArtist)
|
||||
{
|
||||
var artistDict = new Dictionary<int, Core.Music.Artist>();
|
||||
for (var i = 0; i < albums.Count; i++)
|
||||
{
|
||||
var album = albums[i];
|
||||
var resource = result[i];
|
||||
|
||||
var artist = album.Artist ?? artistDict.GetValueOrDefault(albums[i].ArtistId) ?? _artistService.GetArtist(albums[i].ArtistId);
|
||||
artistDict[artist.Id] = artist;
|
||||
|
||||
if (includeArtist)
|
||||
{
|
||||
resource.Artist = artist.ToResource();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < albums.Count; i++)
|
||||
{
|
||||
var resource = result[i];
|
||||
FetchAndLinkAlbumStatistics(resource);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void FetchAndLinkAlbumStatistics(AlbumResource resource)
|
||||
{
|
||||
LinkArtistStatistics(resource, _artistStatisticsService.ArtistStatistics(resource.ArtistId));
|
||||
}
|
||||
|
||||
private void LinkArtistStatistics(AlbumResource resource, ArtistStatistics artistStatistics)
|
||||
{
|
||||
if (artistStatistics.AlbumStatistics != null)
|
||||
{
|
||||
var dictAlbumStats = artistStatistics.AlbumStatistics.ToDictionary(v => v.AlbumId);
|
||||
|
||||
resource.Statistics = dictAlbumStats.GetValueOrDefault(resource.Id).ToResource();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Implement Track or Album Grabbed/Dowloaded Events
|
||||
|
||||
//public void Handle(TrackGrabbedEvent message)
|
||||
//{
|
||||
// foreach (var track in message.Track.Tracks)
|
||||
// {
|
||||
// var resource = track.ToResource();
|
||||
// resource.Grabbed = true;
|
||||
|
||||
// BroadcastResourceChange(ModelAction.Updated, resource);
|
||||
// }
|
||||
//}
|
||||
|
||||
//public void Handle(TrackDownloadedEvent message)
|
||||
//{
|
||||
// foreach (var album in message.Album.Albums)
|
||||
// {
|
||||
// BroadcastResourceChange(ModelAction.Updated, album.Id);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
using NzbDrone.Core.Music;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Api.Music;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
|
||||
namespace NzbDrone.Api.Albums
|
||||
{
|
||||
public class AlbumResource : RestResource
|
||||
{
|
||||
|
||||
public string Title { get; set; }
|
||||
public int ArtistId { get; set; }
|
||||
public List<string> Label { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
public string Path { get; set; }
|
||||
public int ProfileId { get; set; }
|
||||
public int Duration { get; set; }
|
||||
public string AlbumType { get; set; }
|
||||
public Ratings Ratings { get; set; }
|
||||
public DateTime? ReleaseDate { get; set; }
|
||||
public List<string> Genres { get; set; }
|
||||
public ArtistResource Artist { get; set; }
|
||||
public List<MediaCover> Images { get; set; }
|
||||
public AlbumStatisticsResource Statistics { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public static class AlbumResourceMapper
|
||||
{
|
||||
public static AlbumResource ToResource(this Core.Music.Album model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new AlbumResource
|
||||
{
|
||||
Id = model.Id,
|
||||
ArtistId = model.ArtistId,
|
||||
Label = model.Label,
|
||||
Path = model.Path,
|
||||
ProfileId = model.ProfileId,
|
||||
Monitored = model.Monitored,
|
||||
ReleaseDate = model.ReleaseDate,
|
||||
Genres = model.Genres,
|
||||
Title = model.Title,
|
||||
Images = model.Images,
|
||||
Ratings = model.Ratings,
|
||||
Duration = model.Duration,
|
||||
AlbumType = model.AlbumType
|
||||
};
|
||||
}
|
||||
|
||||
public static Album ToModel(this AlbumResource resource)
|
||||
{
|
||||
if (resource == null) return null;
|
||||
|
||||
return new Core.Music.Album
|
||||
{
|
||||
Id = resource.Id,
|
||||
ArtistId = resource.ArtistId,
|
||||
Label = resource.Label,
|
||||
Path = resource.Path,
|
||||
Monitored = resource.Monitored,
|
||||
ProfileId = resource.ProfileId,
|
||||
ReleaseDate = resource.ReleaseDate,
|
||||
Genres = resource.Genres,
|
||||
Title = resource.Title,
|
||||
Images = resource.Images,
|
||||
Ratings = resource.Ratings,
|
||||
AlbumType = resource.AlbumType
|
||||
};
|
||||
}
|
||||
|
||||
public static List<AlbumResource> ToResource(this IEnumerable<Album> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
|
||||
public static List<Album> ToModel(this IEnumerable<AlbumResource> resources)
|
||||
{
|
||||
return resources?.Select(ToModel).ToList() ?? new List<Album>();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
using NzbDrone.Core.Blacklisting;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Blacklist
|
||||
{
|
||||
public class BlacklistModule : LidarrRestModule<BlacklistResource>
|
||||
{
|
||||
private readonly IBlacklistService _blacklistService;
|
||||
|
||||
public BlacklistModule(IBlacklistService blacklistService)
|
||||
{
|
||||
_blacklistService = blacklistService;
|
||||
GetResourcePaged = GetBlacklist;
|
||||
DeleteResource = DeleteBlacklist;
|
||||
}
|
||||
|
||||
private PagingResource<BlacklistResource> GetBlacklist(PagingResource<BlacklistResource> pagingResource)
|
||||
{
|
||||
var pagingSpec = pagingResource.MapToPagingSpec<BlacklistResource, Core.Blacklisting.Blacklist>("id", SortDirection.Ascending);
|
||||
|
||||
return ApplyToPage(_blacklistService.Paged, pagingSpec, BlacklistResourceMapper.MapToResource);
|
||||
}
|
||||
|
||||
private void DeleteBlacklist(int id)
|
||||
{
|
||||
_blacklistService.Delete(id);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Api.Music;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Languages;
|
||||
|
||||
namespace NzbDrone.Api.Blacklist
|
||||
{
|
||||
public class BlacklistResource : RestResource
|
||||
{
|
||||
public int ArtistId { get; set; }
|
||||
public List<int> AlbumIds { get; set; }
|
||||
public string SourceTitle { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public DownloadProtocol Protocol { get; set; }
|
||||
public string Indexer { get; set; }
|
||||
public string Message { get; set; }
|
||||
public Language Language { get; set; }
|
||||
|
||||
public ArtistResource Artist { get; set; }
|
||||
}
|
||||
|
||||
public static class BlacklistResourceMapper
|
||||
{
|
||||
public static BlacklistResource MapToResource(this Core.Blacklisting.Blacklist model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new BlacklistResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
ArtistId = model.ArtistId,
|
||||
AlbumIds = model.AlbumIds,
|
||||
SourceTitle = model.SourceTitle,
|
||||
Quality = model.Quality,
|
||||
Date = model.Date,
|
||||
Protocol = model.Protocol,
|
||||
Indexer = model.Indexer,
|
||||
Message = model.Message,
|
||||
|
||||
Artist = model.Artist.ToResource()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Api.Episodes;
|
||||
using NzbDrone.Api.Albums;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.ArtistStats;
|
||||
using NzbDrone.SignalR;
|
||||
|
||||
namespace NzbDrone.Api.Calendar
|
||||
{
|
||||
public class CalendarModule : AlbumModuleWithSignalR
|
||||
{
|
||||
public CalendarModule(IAlbumService albumService,
|
||||
IArtistStatisticsService artistStatisticsService,
|
||||
IArtistService artistService,
|
||||
IUpgradableSpecification upgradableSpecification,
|
||||
IBroadcastSignalRMessage signalRBroadcaster)
|
||||
: base(albumService, artistStatisticsService, artistService, upgradableSpecification, signalRBroadcaster, "calendar")
|
||||
{
|
||||
GetResourceAll = GetCalendar;
|
||||
}
|
||||
|
||||
private List<AlbumResource> GetCalendar()
|
||||
{
|
||||
var start = DateTime.Today;
|
||||
var end = DateTime.Today.AddDays(2);
|
||||
var includeUnmonitored = false;
|
||||
|
||||
var queryStart = Request.Query.Start;
|
||||
var queryEnd = Request.Query.End;
|
||||
var queryIncludeUnmonitored = Request.Query.Unmonitored;
|
||||
|
||||
if (queryStart.HasValue) start = DateTime.Parse(queryStart.Value);
|
||||
if (queryEnd.HasValue) end = DateTime.Parse(queryEnd.Value);
|
||||
if (queryIncludeUnmonitored.HasValue) includeUnmonitored = Convert.ToBoolean(queryIncludeUnmonitored.Value);
|
||||
|
||||
var resources = MapToResource(_albumService.AlbumsBetweenDates(start, end, includeUnmonitored), true);
|
||||
|
||||
return resources.OrderBy(e => e.ReleaseDate).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Lidarr.Http.Extensions;
|
||||
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 Lidarr.Http;
|
||||
using Lidarr.Http.Mapping;
|
||||
using Lidarr.Http.Validation;
|
||||
|
||||
|
||||
namespace NzbDrone.Api.Commands
|
||||
{
|
||||
public class CommandModule : LidarrRestModuleWithSignalR<CommandResource, CommandModel>, IHandle<CommandUpdatedEvent>
|
||||
{
|
||||
private readonly IManageCommandQueue _commandQueueManager;
|
||||
private readonly IServiceFactory _serviceFactory;
|
||||
|
||||
public CommandModule(IManageCommandQueue commandQueueManager,
|
||||
IBroadcastSignalRMessage signalRBroadcaster,
|
||||
IServiceFactory serviceFactory)
|
||||
: base(signalRBroadcaster)
|
||||
{
|
||||
_commandQueueManager = commandQueueManager;
|
||||
_serviceFactory = serviceFactory;
|
||||
|
||||
GetResourceById = GetCommand;
|
||||
CreateResource = StartCommand;
|
||||
GetResourceAll = GetStartedCommands;
|
||||
|
||||
PostValidator.RuleFor(c => c.Name).NotBlank();
|
||||
}
|
||||
|
||||
private CommandResource GetCommand(int id)
|
||||
{
|
||||
return _commandQueueManager.Get(id).ToResource();
|
||||
}
|
||||
|
||||
private int StartCommand(CommandResource commandResource)
|
||||
{
|
||||
var commandType = _serviceFactory.GetImplementations(typeof(Command))
|
||||
.Single(c => c.Name.Replace("Command", "").Equals(commandResource.Name, StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
dynamic command = Request.Body.FromJson(commandType);
|
||||
command.Trigger = CommandTrigger.Manual;
|
||||
|
||||
var trackedCommand = _commandQueueManager.Push(command, CommandPriority.Normal, CommandTrigger.Manual);
|
||||
return trackedCommand.Id;
|
||||
}
|
||||
|
||||
private List<CommandResource> GetStartedCommands()
|
||||
{
|
||||
return _commandQueueManager.GetStarted().ToResource();
|
||||
}
|
||||
|
||||
public void Handle(CommandUpdatedEvent message)
|
||||
{
|
||||
if (message.Command.Body.SendUpdatesToClient)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Updated, message.Command.ToResource());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
|
||||
namespace NzbDrone.Api.Commands
|
||||
{
|
||||
public class CommandResource : RestResource
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Message { get; set; }
|
||||
public object Body { get; set; }
|
||||
public CommandPriority Priority { get; set; }
|
||||
public CommandStatus Status { get; set; }
|
||||
public DateTime Queued { get; set; }
|
||||
public DateTime? Started { get; set; }
|
||||
public DateTime? Ended { get; set; }
|
||||
public TimeSpan? Duration { get; set; }
|
||||
public string Exception { get; set; }
|
||||
public CommandTrigger Trigger { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public string CompletionMessage { get; set; }
|
||||
|
||||
//Legacy
|
||||
public CommandStatus State
|
||||
{
|
||||
get
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
set { }
|
||||
}
|
||||
|
||||
public bool Manual
|
||||
{
|
||||
get
|
||||
{
|
||||
return Trigger == CommandTrigger.Manual;
|
||||
}
|
||||
|
||||
set { }
|
||||
}
|
||||
|
||||
public DateTime StartedOn
|
||||
{
|
||||
get
|
||||
{
|
||||
return Queued;
|
||||
}
|
||||
|
||||
set { }
|
||||
}
|
||||
|
||||
public DateTime? StateChangeTime
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
if (Started.HasValue) return Started.Value;
|
||||
|
||||
return Ended;
|
||||
}
|
||||
|
||||
set { }
|
||||
}
|
||||
|
||||
public bool SendUpdatesToClient
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Body != null) return (Body as Command).SendUpdatesToClient;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
set { }
|
||||
}
|
||||
|
||||
public bool UpdateScheduledTask
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Body != null) return (Body as Command).UpdateScheduledTask;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
set { }
|
||||
}
|
||||
|
||||
public DateTime? LastExecutionTime { get; set; }
|
||||
}
|
||||
|
||||
public static class CommandResourceMapper
|
||||
{
|
||||
public static CommandResource ToResource(this CommandModel model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new CommandResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
Name = model.Name,
|
||||
Message = model.Message,
|
||||
Body = model.Body,
|
||||
Priority = model.Priority,
|
||||
Status = model.Status,
|
||||
Queued = model.QueuedAt,
|
||||
Started = model.StartedAt,
|
||||
Ended = model.EndedAt,
|
||||
Duration = model.Duration,
|
||||
Exception = model.Exception,
|
||||
Trigger = model.Trigger,
|
||||
|
||||
CompletionMessage = model.Body.CompletionMessage,
|
||||
LastExecutionTime = model.Body.LastExecutionTime
|
||||
};
|
||||
}
|
||||
|
||||
public static List<CommandResource> ToResource(this IEnumerable<CommandModel> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Validation.Paths;
|
||||
|
||||
namespace NzbDrone.Api.Config
|
||||
{
|
||||
public class DownloadClientConfigModule : NzbDroneConfigModule<DownloadClientConfigResource>
|
||||
{
|
||||
public DownloadClientConfigModule(IConfigService configService)
|
||||
: base(configService)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override DownloadClientConfigResource ToResource(IConfigService model)
|
||||
{
|
||||
return DownloadClientConfigResourceMapper.ToResource(model);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace NzbDrone.Api.Config
|
||||
{
|
||||
public class DownloadClientConfigResource : RestResource
|
||||
{
|
||||
public string DownloadClientWorkingFolders { get; set; }
|
||||
|
||||
public bool EnableCompletedDownloadHandling { get; set; }
|
||||
public bool RemoveCompletedDownloads { get; set; }
|
||||
|
||||
public bool AutoRedownloadFailed { get; set; }
|
||||
public bool RemoveFailedDownloads { get; set; }
|
||||
}
|
||||
|
||||
public static class DownloadClientConfigResourceMapper
|
||||
{
|
||||
public static DownloadClientConfigResource ToResource(IConfigService model)
|
||||
{
|
||||
return new DownloadClientConfigResource
|
||||
{
|
||||
DownloadClientWorkingFolders = model.DownloadClientWorkingFolders,
|
||||
|
||||
EnableCompletedDownloadHandling = model.EnableCompletedDownloadHandling,
|
||||
RemoveCompletedDownloads = model.RemoveCompletedDownloads,
|
||||
|
||||
AutoRedownloadFailed = model.AutoRedownloadFailed,
|
||||
RemoveFailedDownloads = model.RemoveFailedDownloads
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Authentication;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Update;
|
||||
using NzbDrone.Core.Validation;
|
||||
using NzbDrone.Core.Validation.Paths;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Config
|
||||
{
|
||||
public class HostConfigModule : LidarrRestModule<HostConfigResource>
|
||||
{
|
||||
private readonly IConfigFileProvider _configFileProvider;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IUserService _userService;
|
||||
|
||||
public HostConfigModule(IConfigFileProvider configFileProvider, IConfigService configService, IUserService userService)
|
||||
: base("/config/host")
|
||||
{
|
||||
_configFileProvider = configFileProvider;
|
||||
_configService = configService;
|
||||
_userService = userService;
|
||||
|
||||
GetResourceSingle = GetHostConfig;
|
||||
GetResourceById = GetHostConfig;
|
||||
UpdateResource = SaveHostConfig;
|
||||
|
||||
SharedValidator.RuleFor(c => c.BindAddress)
|
||||
.ValidIp4Address()
|
||||
.NotListenAllIp4Address()
|
||||
.When(c => c.BindAddress != "*");
|
||||
|
||||
SharedValidator.RuleFor(c => c.Port).ValidPort();
|
||||
|
||||
SharedValidator.RuleFor(c => c.UrlBase).ValidUrlBase();
|
||||
|
||||
SharedValidator.RuleFor(c => c.Username).NotEmpty().When(c => c.AuthenticationMethod != AuthenticationType.None);
|
||||
SharedValidator.RuleFor(c => c.Password).NotEmpty().When(c => c.AuthenticationMethod != AuthenticationType.None);
|
||||
|
||||
SharedValidator.RuleFor(c => c.SslPort).ValidPort().When(c => c.EnableSsl);
|
||||
SharedValidator.RuleFor(c => c.SslCertHash).NotEmpty().When(c => c.EnableSsl && OsInfo.IsWindows);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private HostConfigResource GetHostConfig()
|
||||
{
|
||||
var resource = _configFileProvider.ToResource(_configService);
|
||||
resource.Id = 1;
|
||||
|
||||
var user = _userService.FindUser();
|
||||
if (user != null)
|
||||
{
|
||||
resource.Username = user.Username;
|
||||
resource.Password = user.Password;
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
private HostConfigResource GetHostConfig(int id)
|
||||
{
|
||||
return GetHostConfig();
|
||||
}
|
||||
|
||||
private void SaveHostConfig(HostConfigResource resource)
|
||||
{
|
||||
var dictionary = resource.GetType()
|
||||
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
.ToDictionary(prop => prop.Name, prop => prop.GetValue(resource, null));
|
||||
|
||||
_configFileProvider.SaveConfigDictionary(dictionary);
|
||||
_configService.SaveConfigDictionary(dictionary);
|
||||
|
||||
if (resource.Username.IsNotNullOrWhiteSpace() && resource.Password.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
_userService.Upsert(resource.Username, resource.Password);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Authentication;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Update;
|
||||
using NzbDrone.Common.Http.Proxy;
|
||||
|
||||
namespace NzbDrone.Api.Config
|
||||
{
|
||||
public class HostConfigResource : RestResource
|
||||
{
|
||||
public string BindAddress { get; set; }
|
||||
public int Port { get; set; }
|
||||
public int SslPort { get; set; }
|
||||
public bool EnableSsl { get; set; }
|
||||
public bool LaunchBrowser { get; set; }
|
||||
public AuthenticationType AuthenticationMethod { get; set; }
|
||||
public bool AnalyticsEnabled { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string LogLevel { get; set; }
|
||||
public string Branch { get; set; }
|
||||
public string ApiKey { get; set; }
|
||||
public string SslCertHash { get; set; }
|
||||
public string UrlBase { get; set; }
|
||||
public bool UpdateAutomatically { get; set; }
|
||||
public UpdateMechanism UpdateMechanism { get; set; }
|
||||
public string UpdateScriptPath { get; set; }
|
||||
public bool ProxyEnabled { get; set; }
|
||||
public ProxyType ProxyType { get; set; }
|
||||
public string ProxyHostname { get; set; }
|
||||
public int ProxyPort { get; set; }
|
||||
public string ProxyUsername { get; set; }
|
||||
public string ProxyPassword { get; set; }
|
||||
public string ProxyBypassFilter { get; set; }
|
||||
public bool ProxyBypassLocalAddresses { get; set; }
|
||||
}
|
||||
|
||||
public static class HostConfigResourceMapper
|
||||
{
|
||||
public static HostConfigResource ToResource(this IConfigFileProvider model, IConfigService configService)
|
||||
{
|
||||
// TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead?
|
||||
return new HostConfigResource
|
||||
{
|
||||
BindAddress = model.BindAddress,
|
||||
Port = model.Port,
|
||||
SslPort = model.SslPort,
|
||||
EnableSsl = model.EnableSsl,
|
||||
LaunchBrowser = model.LaunchBrowser,
|
||||
AuthenticationMethod = model.AuthenticationMethod,
|
||||
AnalyticsEnabled = model.AnalyticsEnabled,
|
||||
//Username
|
||||
//Password
|
||||
LogLevel = model.LogLevel,
|
||||
Branch = model.Branch,
|
||||
ApiKey = model.ApiKey,
|
||||
SslCertHash = model.SslCertHash,
|
||||
UrlBase = model.UrlBase,
|
||||
UpdateAutomatically = model.UpdateAutomatically,
|
||||
UpdateMechanism = model.UpdateMechanism,
|
||||
UpdateScriptPath = model.UpdateScriptPath,
|
||||
ProxyEnabled = configService.ProxyEnabled,
|
||||
ProxyType = configService.ProxyType,
|
||||
ProxyHostname = configService.ProxyHostname,
|
||||
ProxyPort = configService.ProxyPort,
|
||||
ProxyUsername = configService.ProxyUsername,
|
||||
ProxyPassword = configService.ProxyPassword,
|
||||
ProxyBypassFilter = configService.ProxyBypassFilter,
|
||||
ProxyBypassLocalAddresses = configService.ProxyBypassLocalAddresses
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
using FluentValidation;
|
||||
using Lidarr.Http.Validation;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace NzbDrone.Api.Config
|
||||
{
|
||||
public class IndexerConfigModule : NzbDroneConfigModule<IndexerConfigResource>
|
||||
{
|
||||
|
||||
public IndexerConfigModule(IConfigService configService)
|
||||
: base(configService)
|
||||
{
|
||||
SharedValidator.RuleFor(c => c.MinimumAge)
|
||||
.GreaterThanOrEqualTo(0);
|
||||
|
||||
SharedValidator.RuleFor(c => c.Retention)
|
||||
.GreaterThanOrEqualTo(0);
|
||||
|
||||
SharedValidator.RuleFor(c => c.RssSyncInterval)
|
||||
.IsValidRssSyncInterval();
|
||||
}
|
||||
|
||||
protected override IndexerConfigResource ToResource(IConfigService model)
|
||||
{
|
||||
return IndexerConfigResourceMapper.ToResource(model);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace NzbDrone.Api.Config
|
||||
{
|
||||
public class IndexerConfigResource : RestResource
|
||||
{
|
||||
public int MinimumAge { get; set; }
|
||||
public int Retention { get; set; }
|
||||
public int RssSyncInterval { get; set; }
|
||||
}
|
||||
|
||||
public static class IndexerConfigResourceMapper
|
||||
{
|
||||
public static IndexerConfigResource ToResource(IConfigService model)
|
||||
{
|
||||
return new IndexerConfigResource
|
||||
{
|
||||
MinimumAge = model.MinimumAge,
|
||||
Retention = model.Retention,
|
||||
RssSyncInterval = model.RssSyncInterval,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
|
||||
namespace NzbDrone.Api.Config
|
||||
{
|
||||
public class MediaManagementConfigResource : RestResource
|
||||
{
|
||||
public bool AutoUnmonitorPreviouslyDownloadedTracks { get; set; }
|
||||
public string RecycleBin { get; set; }
|
||||
public bool AutoDownloadPropers { get; set; }
|
||||
public bool CreateEmptyArtistFolders { get; set; }
|
||||
public FileDateType FileDate { get; set; }
|
||||
|
||||
public bool SetPermissionsLinux { get; set; }
|
||||
public string FileChmod { get; set; }
|
||||
public string FolderChmod { get; set; }
|
||||
public string ChownUser { get; set; }
|
||||
public string ChownGroup { get; set; }
|
||||
|
||||
public bool SkipFreeSpaceCheckWhenImporting { get; set; }
|
||||
public bool CopyUsingHardlinks { get; set; }
|
||||
public bool ImportExtraFiles { get; set; }
|
||||
public string ExtraFileExtensions { get; set; }
|
||||
public bool EnableMediaInfo { get; set; }
|
||||
}
|
||||
|
||||
public static class MediaManagementConfigResourceMapper
|
||||
{
|
||||
public static MediaManagementConfigResource ToResource(IConfigService model)
|
||||
{
|
||||
return new MediaManagementConfigResource
|
||||
{
|
||||
AutoUnmonitorPreviouslyDownloadedTracks = model.AutoUnmonitorPreviouslyDownloadedTracks,
|
||||
RecycleBin = model.RecycleBin,
|
||||
AutoDownloadPropers = model.AutoDownloadPropers,
|
||||
CreateEmptyArtistFolders = model.CreateEmptyArtistFolders,
|
||||
FileDate = model.FileDate,
|
||||
|
||||
SetPermissionsLinux = model.SetPermissionsLinux,
|
||||
FileChmod = model.FileChmod,
|
||||
FolderChmod = model.FolderChmod,
|
||||
ChownUser = model.ChownUser,
|
||||
ChownGroup = model.ChownGroup,
|
||||
|
||||
SkipFreeSpaceCheckWhenImporting = model.SkipFreeSpaceCheckWhenImporting,
|
||||
CopyUsingHardlinks = model.CopyUsingHardlinks,
|
||||
ImportExtraFiles = model.ImportExtraFiles,
|
||||
ExtraFileExtensions = model.ExtraFileExtensions,
|
||||
EnableMediaInfo = model.EnableMediaInfo
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentValidation;
|
||||
using FluentValidation.Results;
|
||||
using Nancy.Responses;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using Nancy.ModelBinding;
|
||||
using Lidarr.Http.Extensions;
|
||||
using Lidarr.Http;
|
||||
using Lidarr.Http.Mapping;
|
||||
|
||||
namespace NzbDrone.Api.Config
|
||||
{
|
||||
public class NamingConfigModule : LidarrRestModule<NamingConfigResource>
|
||||
{
|
||||
private readonly INamingConfigService _namingConfigService;
|
||||
private readonly IFilenameSampleService _filenameSampleService;
|
||||
private readonly IFilenameValidationService _filenameValidationService;
|
||||
private readonly IBuildFileNames _filenameBuilder;
|
||||
|
||||
public NamingConfigModule(INamingConfigService namingConfigService,
|
||||
IFilenameSampleService filenameSampleService,
|
||||
IFilenameValidationService filenameValidationService,
|
||||
IBuildFileNames filenameBuilder)
|
||||
: base("config/naming")
|
||||
{
|
||||
_namingConfigService = namingConfigService;
|
||||
_filenameSampleService = filenameSampleService;
|
||||
_filenameValidationService = filenameValidationService;
|
||||
_filenameBuilder = filenameBuilder;
|
||||
GetResourceSingle = GetNamingConfig;
|
||||
GetResourceById = GetNamingConfig;
|
||||
UpdateResource = UpdateNamingConfig;
|
||||
|
||||
Get["/samples"] = x => GetExamples(this.Bind<NamingConfigResource>());
|
||||
|
||||
SharedValidator.RuleFor(c => c.MultiEpisodeStyle).InclusiveBetween(0, 5);
|
||||
SharedValidator.RuleFor(c => c.StandardTrackFormat).ValidTrackFormat();
|
||||
SharedValidator.RuleFor(c => c.ArtistFolderFormat).ValidArtistFolderFormat();
|
||||
SharedValidator.RuleFor(c => c.AlbumFolderFormat).ValidAlbumFolderFormat();
|
||||
}
|
||||
|
||||
private void UpdateNamingConfig(NamingConfigResource resource)
|
||||
{
|
||||
var nameSpec = resource.ToModel();
|
||||
ValidateFormatResult(nameSpec);
|
||||
|
||||
_namingConfigService.Save(nameSpec);
|
||||
}
|
||||
|
||||
private NamingConfigResource GetNamingConfig()
|
||||
{
|
||||
var nameSpec = _namingConfigService.GetConfig();
|
||||
var resource = nameSpec.ToResource();
|
||||
|
||||
if (resource.StandardTrackFormat.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var basicConfig = _filenameBuilder.GetBasicNamingConfig(nameSpec);
|
||||
basicConfig.AddToResource(resource);
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
private NamingConfigResource GetNamingConfig(int id)
|
||||
{
|
||||
return GetNamingConfig();
|
||||
}
|
||||
|
||||
private JsonResponse<NamingSampleResource> GetExamples(NamingConfigResource config)
|
||||
{
|
||||
var nameSpec = config.ToModel();
|
||||
var sampleResource = new NamingSampleResource();
|
||||
|
||||
|
||||
var singleTrackSampleResult = _filenameSampleService.GetStandardTrackSample(nameSpec);
|
||||
|
||||
sampleResource.SingleTrackExample = _filenameValidationService.ValidateTrackFilename(singleTrackSampleResult) != null
|
||||
? "Invalid format"
|
||||
: singleTrackSampleResult.FileName;
|
||||
|
||||
sampleResource.ArtistFolderExample = nameSpec.ArtistFolderFormat.IsNullOrWhiteSpace()
|
||||
? "Invalid format"
|
||||
: _filenameSampleService.GetArtistFolderSample(nameSpec);
|
||||
|
||||
sampleResource.AlbumFolderExample = nameSpec.AlbumFolderFormat.IsNullOrWhiteSpace()
|
||||
? "Invalid format"
|
||||
: _filenameSampleService.GetAlbumFolderSample(nameSpec);
|
||||
|
||||
return sampleResource.AsResponse();
|
||||
}
|
||||
|
||||
private void ValidateFormatResult(NamingConfig nameSpec)
|
||||
{
|
||||
|
||||
var singleTrackSampleResult = _filenameSampleService.GetStandardTrackSample(nameSpec);
|
||||
|
||||
var singleTrackValidationResult = _filenameValidationService.ValidateTrackFilename(singleTrackSampleResult);
|
||||
|
||||
var validationFailures = new List<ValidationFailure>();
|
||||
|
||||
validationFailures.AddIfNotNull(singleTrackValidationResult);
|
||||
|
||||
|
||||
if (validationFailures.Any())
|
||||
{
|
||||
throw new ValidationException(validationFailures.DistinctBy(v => v.PropertyName).ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Organizer;
|
||||
|
||||
namespace NzbDrone.Api.Config
|
||||
{
|
||||
public class NamingConfigResource : RestResource
|
||||
{
|
||||
public bool RenameTracks { get; set; }
|
||||
public bool ReplaceIllegalCharacters { get; set; }
|
||||
public int MultiEpisodeStyle { get; set; }
|
||||
public string StandardTrackFormat { get; set; }
|
||||
public string ArtistFolderFormat { get; set; }
|
||||
public string AlbumFolderFormat { get; set; }
|
||||
public bool IncludeArtistName { get; set; }
|
||||
public bool IncludeAlbumTitle { get; set; }
|
||||
public bool IncludeQuality { get; set; }
|
||||
public bool ReplaceSpaces { get; set; }
|
||||
public string Separator { get; set; }
|
||||
public string NumberStyle { get; set; }
|
||||
}
|
||||
|
||||
public static class NamingConfigResourceMapper
|
||||
{
|
||||
public static NamingConfigResource ToResource(this NamingConfig model)
|
||||
{
|
||||
return new NamingConfigResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
RenameTracks = model.RenameTracks,
|
||||
ReplaceIllegalCharacters = model.ReplaceIllegalCharacters,
|
||||
StandardTrackFormat = model.StandardTrackFormat,
|
||||
ArtistFolderFormat = model.ArtistFolderFormat,
|
||||
AlbumFolderFormat = model.AlbumFolderFormat
|
||||
//IncludeSeriesTitle
|
||||
//IncludeEpisodeTitle
|
||||
//IncludeQuality
|
||||
//ReplaceSpaces
|
||||
//Separator
|
||||
//NumberStyle
|
||||
};
|
||||
}
|
||||
|
||||
public static void AddToResource(this BasicNamingConfig basicNamingConfig, NamingConfigResource resource)
|
||||
{
|
||||
resource.IncludeArtistName = basicNamingConfig.IncludeArtistName;
|
||||
resource.IncludeAlbumTitle = basicNamingConfig.IncludeAlbumTitle;
|
||||
resource.IncludeQuality = basicNamingConfig.IncludeQuality;
|
||||
resource.ReplaceSpaces = basicNamingConfig.ReplaceSpaces;
|
||||
resource.Separator = basicNamingConfig.Separator;
|
||||
resource.NumberStyle = basicNamingConfig.NumberStyle;
|
||||
}
|
||||
|
||||
public static NamingConfig ToModel(this NamingConfigResource resource)
|
||||
{
|
||||
return new NamingConfig
|
||||
{
|
||||
Id = resource.Id,
|
||||
|
||||
RenameTracks = resource.RenameTracks,
|
||||
ReplaceIllegalCharacters = resource.ReplaceIllegalCharacters,
|
||||
StandardTrackFormat = resource.StandardTrackFormat,
|
||||
ArtistFolderFormat = resource.ArtistFolderFormat,
|
||||
AlbumFolderFormat = resource.AlbumFolderFormat
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Config
|
||||
{
|
||||
public abstract class NzbDroneConfigModule<TResource> : LidarrRestModule<TResource> where TResource : RestResource, new()
|
||||
{
|
||||
private readonly IConfigService _configService;
|
||||
|
||||
protected NzbDroneConfigModule(IConfigService configService)
|
||||
: this(new TResource().ResourceName.Replace("config", ""), configService)
|
||||
{
|
||||
}
|
||||
|
||||
protected NzbDroneConfigModule(string resource, IConfigService configService) :
|
||||
base("config/" + resource.Trim('/'))
|
||||
{
|
||||
_configService = configService;
|
||||
|
||||
GetResourceSingle = GetConfig;
|
||||
GetResourceById = GetConfig;
|
||||
UpdateResource = SaveConfig;
|
||||
}
|
||||
|
||||
private TResource GetConfig()
|
||||
{
|
||||
var resource = ToResource(_configService);
|
||||
resource.Id = 1;
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
protected abstract TResource ToResource(IConfigService model);
|
||||
|
||||
private TResource GetConfig(int id)
|
||||
{
|
||||
return GetConfig();
|
||||
}
|
||||
|
||||
private void SaveConfig(TResource resource)
|
||||
{
|
||||
var dictionary = resource.GetType()
|
||||
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
.ToDictionary(prop => prop.Name, prop => prop.GetValue(resource, null));
|
||||
|
||||
_configService.SaveConfigDictionary(dictionary);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace NzbDrone.Api.Config
|
||||
{
|
||||
public class UiConfigResource : RestResource
|
||||
{
|
||||
//Calendar
|
||||
public int FirstDayOfWeek { get; set; }
|
||||
public string CalendarWeekColumnHeader { get; set; }
|
||||
|
||||
//Dates
|
||||
public string ShortDateFormat { get; set; }
|
||||
public string LongDateFormat { get; set; }
|
||||
public string TimeFormat { get; set; }
|
||||
public bool ShowRelativeDates { get; set; }
|
||||
|
||||
public bool EnableColorImpairedMode { get; set; }
|
||||
}
|
||||
|
||||
public static class UiConfigResourceMapper
|
||||
{
|
||||
public static UiConfigResource ToResource(IConfigService model)
|
||||
{
|
||||
return new UiConfigResource
|
||||
{
|
||||
FirstDayOfWeek = model.FirstDayOfWeek,
|
||||
CalendarWeekColumnHeader = model.CalendarWeekColumnHeader,
|
||||
|
||||
ShortDateFormat = model.ShortDateFormat,
|
||||
LongDateFormat = model.LongDateFormat,
|
||||
TimeFormat = model.TimeFormat,
|
||||
ShowRelativeDates = model.ShowRelativeDates,
|
||||
|
||||
EnableColorImpairedMode = model.EnableColorImpairedMode,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.DiskSpace;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.DiskSpace
|
||||
{
|
||||
public class DiskSpaceModule : LidarrRestModule<DiskSpaceResource>
|
||||
{
|
||||
private readonly IDiskSpaceService _diskSpaceService;
|
||||
|
||||
public DiskSpaceModule(IDiskSpaceService diskSpaceService)
|
||||
: base("diskspace")
|
||||
{
|
||||
_diskSpaceService = diskSpaceService;
|
||||
GetResourceAll = GetFreeSpace;
|
||||
}
|
||||
|
||||
|
||||
public List<DiskSpaceResource> GetFreeSpace()
|
||||
{
|
||||
return _diskSpaceService.GetFreeSpace().ConvertAll(DiskSpaceResourceMapper.MapToResource);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
using Lidarr.Http.REST;
|
||||
|
||||
namespace NzbDrone.Api.DiskSpace
|
||||
{
|
||||
public class DiskSpaceResource : RestResource
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public string Label { get; set; }
|
||||
public long FreeSpace { get; set; }
|
||||
public long TotalSpace { get; set; }
|
||||
}
|
||||
|
||||
public static class DiskSpaceResourceMapper
|
||||
{
|
||||
public static DiskSpaceResource MapToResource(this Core.DiskSpace.DiskSpace model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new DiskSpaceResource
|
||||
{
|
||||
Path = model.Path,
|
||||
Label = model.Label,
|
||||
FreeSpace = model.FreeSpace,
|
||||
TotalSpace = model.TotalSpace
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using Lidarr.Http;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.SignalR;
|
||||
using System;
|
||||
|
||||
namespace NzbDrone.Api.EpisodeFiles
|
||||
{
|
||||
public class EpisodeFileModule : LidarrRestModuleWithSignalR<EpisodeFileResource, EpisodeFile>,
|
||||
IHandle<EpisodeFileAddedEvent>
|
||||
{
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IRecycleBinProvider _recycleBinProvider;
|
||||
private readonly ISeriesService _seriesService;
|
||||
private readonly IUpgradableSpecification _upgradableSpecification;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public EpisodeFileModule(IBroadcastSignalRMessage signalRBroadcaster,
|
||||
IMediaFileService mediaFileService,
|
||||
IDiskProvider diskProvider,
|
||||
IRecycleBinProvider recycleBinProvider,
|
||||
ISeriesService seriesService,
|
||||
IUpgradableSpecification upgradableSpecification,
|
||||
Logger logger)
|
||||
: base(signalRBroadcaster)
|
||||
{
|
||||
_mediaFileService = mediaFileService;
|
||||
_diskProvider = diskProvider;
|
||||
_recycleBinProvider = recycleBinProvider;
|
||||
_seriesService = seriesService;
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_logger = logger;
|
||||
GetResourceById = GetEpisodeFile;
|
||||
GetResourceAll = GetEpisodeFiles;
|
||||
UpdateResource = SetQuality;
|
||||
DeleteResource = DeleteEpisodeFile;
|
||||
}
|
||||
|
||||
private EpisodeFileResource GetEpisodeFile(int id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
//var episodeFile = _mediaFileService.Get(id);
|
||||
//var series = _seriesService.GetSeries(episodeFile.SeriesId);
|
||||
|
||||
//return episodeFile.ToResource(series, _qualityUpgradableSpecification);
|
||||
}
|
||||
|
||||
private List<EpisodeFileResource> GetEpisodeFiles()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
//if (!Request.Query.SeriesId.HasValue)
|
||||
//{
|
||||
// throw new BadRequestException("seriesId is missing");
|
||||
//}
|
||||
|
||||
//var seriesId = (int)Request.Query.SeriesId;
|
||||
|
||||
//var series = _seriesService.GetSeries(seriesId);
|
||||
|
||||
//return _mediaFileService.GetFilesBySeries(seriesId).ConvertAll(f => f.ToResource(series, _qualityUpgradableSpecification));
|
||||
}
|
||||
|
||||
private void SetQuality(EpisodeFileResource episodeFileResource)
|
||||
{
|
||||
var episodeFile = _mediaFileService.Get(episodeFileResource.Id);
|
||||
episodeFile.Quality = episodeFileResource.Quality;
|
||||
_mediaFileService.Update(episodeFile);
|
||||
}
|
||||
|
||||
private void DeleteEpisodeFile(int id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
//var episodeFile = _mediaFileService.Get(id);
|
||||
//var series = _seriesService.GetSeries(episodeFile.SeriesId);
|
||||
//var fullPath = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
//var subfolder = _diskProvider.GetParentFolder(series.Path).GetRelativePath(_diskProvider.GetParentFolder(fullPath));
|
||||
|
||||
//_logger.Info("Deleting episode file: {0}", fullPath);
|
||||
//_recycleBinProvider.DeleteFile(fullPath, subfolder);
|
||||
//_mediaFileService.Delete(episodeFile, DeleteMediaFileReason.Manual);
|
||||
}
|
||||
|
||||
public void Handle(EpisodeFileAddedEvent message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Updated, message.EpisodeFile.Id);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Languages;
|
||||
|
||||
namespace NzbDrone.Api.EpisodeFiles
|
||||
{
|
||||
public class EpisodeFileResource : RestResource
|
||||
{
|
||||
public int SeriesId { get; set; }
|
||||
public int SeasonNumber { get; set; }
|
||||
public string RelativePath { get; set; }
|
||||
public string Path { get; set; }
|
||||
public long Size { get; set; }
|
||||
public DateTime DateAdded { get; set; }
|
||||
public string SceneName { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public Language Language { get; set; }
|
||||
|
||||
public bool QualityCutoffNotMet { get; set; }
|
||||
}
|
||||
|
||||
public static class EpisodeFileResourceMapper
|
||||
{
|
||||
private static EpisodeFileResource ToResource(this EpisodeFile model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new EpisodeFileResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
SeriesId = model.SeriesId,
|
||||
SeasonNumber = model.SeasonNumber,
|
||||
RelativePath = model.RelativePath,
|
||||
//Path
|
||||
Size = model.Size,
|
||||
DateAdded = model.DateAdded,
|
||||
SceneName = model.SceneName,
|
||||
Quality = model.Quality,
|
||||
//QualityCutoffNotMet
|
||||
};
|
||||
}
|
||||
|
||||
public static EpisodeFileResource ToResource(this EpisodeFile model, Core.Tv.Series series, IUpgradableSpecification upgradableSpecification)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new EpisodeFileResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
SeriesId = model.SeriesId,
|
||||
SeasonNumber = model.SeasonNumber,
|
||||
RelativePath = model.RelativePath,
|
||||
Path = Path.Combine(series.Path, model.RelativePath),
|
||||
Size = model.Size,
|
||||
DateAdded = model.DateAdded,
|
||||
SceneName = model.SceneName,
|
||||
Quality = model.Quality,
|
||||
Language = model.Language,
|
||||
QualityCutoffNotMet = upgradableSpecification.CutoffNotMet(series.Profile.Value, series.LanguageProfile.Value, model.Quality, model.Language)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.SignalR;
|
||||
|
||||
namespace NzbDrone.Api.Episodes
|
||||
{
|
||||
public class EpisodeModule : EpisodeModuleWithSignalR
|
||||
{
|
||||
public EpisodeModule(ISeriesService seriesService,
|
||||
IEpisodeService episodeService,
|
||||
IUpgradableSpecification qualityUpgradableSpecification,
|
||||
IBroadcastSignalRMessage signalRBroadcaster)
|
||||
: base(episodeService, seriesService, qualityUpgradableSpecification, signalRBroadcaster)
|
||||
{
|
||||
GetResourceAll = GetEpisodes;
|
||||
UpdateResource = SetMonitored;
|
||||
}
|
||||
|
||||
private List<EpisodeResource> GetEpisodes()
|
||||
{
|
||||
if (!Request.Query.SeriesId.HasValue)
|
||||
{
|
||||
throw new BadRequestException("seriesId is missing");
|
||||
}
|
||||
|
||||
var seriesId = (int)Request.Query.SeriesId;
|
||||
|
||||
var resources = MapToResource(_episodeService.GetEpisodeBySeries(seriesId), false, true);
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
private void SetMonitored(EpisodeResource episodeResource)
|
||||
{
|
||||
_episodeService.SetEpisodeMonitored(episodeResource.Id, episodeResource.Monitored);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Api.EpisodeFiles;
|
||||
using NzbDrone.Api.Series;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.SignalR;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Episodes
|
||||
{
|
||||
public abstract class EpisodeModuleWithSignalR : LidarrRestModuleWithSignalR<EpisodeResource, Episode>,
|
||||
IHandle<EpisodeGrabbedEvent>,
|
||||
IHandle<EpisodeDownloadedEvent>
|
||||
{
|
||||
protected readonly IEpisodeService _episodeService;
|
||||
protected readonly ISeriesService _seriesService;
|
||||
protected readonly IUpgradableSpecification _qualityUpgradableSpecification;
|
||||
|
||||
protected EpisodeModuleWithSignalR(IEpisodeService episodeService,
|
||||
ISeriesService seriesService,
|
||||
IUpgradableSpecification qualityUpgradableSpecification,
|
||||
IBroadcastSignalRMessage signalRBroadcaster)
|
||||
: base(signalRBroadcaster)
|
||||
{
|
||||
_episodeService = episodeService;
|
||||
_seriesService = seriesService;
|
||||
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||
|
||||
GetResourceById = GetEpisode;
|
||||
}
|
||||
|
||||
protected EpisodeModuleWithSignalR(IEpisodeService episodeService,
|
||||
ISeriesService seriesService,
|
||||
IUpgradableSpecification qualityUpgradableSpecification,
|
||||
IBroadcastSignalRMessage signalRBroadcaster,
|
||||
string resource)
|
||||
: base(signalRBroadcaster, resource)
|
||||
{
|
||||
_episodeService = episodeService;
|
||||
_seriesService = seriesService;
|
||||
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||
|
||||
GetResourceById = GetEpisode;
|
||||
}
|
||||
|
||||
protected EpisodeResource GetEpisode(int id)
|
||||
{
|
||||
var episode = _episodeService.GetEpisode(id);
|
||||
var resource = MapToResource(episode, true, true);
|
||||
return resource;
|
||||
}
|
||||
|
||||
protected EpisodeResource MapToResource(Episode episode, bool includeSeries, bool includeEpisodeFile)
|
||||
{
|
||||
var resource = episode.ToResource();
|
||||
|
||||
if (includeSeries || includeEpisodeFile)
|
||||
{
|
||||
var series = episode.Series ?? _seriesService.GetSeries(episode.SeriesId);
|
||||
|
||||
if (includeSeries)
|
||||
{
|
||||
resource.Series = series.ToResource();
|
||||
}
|
||||
if (includeEpisodeFile && episode.EpisodeFileId != 0)
|
||||
{
|
||||
resource.EpisodeFile = episode.EpisodeFile.Value.ToResource(series, _qualityUpgradableSpecification);
|
||||
}
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
protected List<EpisodeResource> MapToResource(List<Episode> episodes, bool includeSeries, bool includeEpisodeFile)
|
||||
{
|
||||
var result = episodes.ToResource();
|
||||
|
||||
if (includeSeries || includeEpisodeFile)
|
||||
{
|
||||
var seriesDict = new Dictionary<int, Core.Tv.Series>();
|
||||
for (var i = 0; i < episodes.Count; i++)
|
||||
{
|
||||
var episode = episodes[i];
|
||||
var resource = result[i];
|
||||
|
||||
var series = episode.Series ?? seriesDict.GetValueOrDefault(episodes[i].SeriesId) ?? _seriesService.GetSeries(episodes[i].SeriesId);
|
||||
seriesDict[series.Id] = series;
|
||||
|
||||
if (includeSeries)
|
||||
{
|
||||
resource.Series = series.ToResource();
|
||||
}
|
||||
if (includeEpisodeFile && episodes[i].EpisodeFileId != 0)
|
||||
{
|
||||
resource.EpisodeFile = episodes[i].EpisodeFile.Value.ToResource(series, _qualityUpgradableSpecification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Handle(EpisodeGrabbedEvent message)
|
||||
{
|
||||
foreach (var episode in message.Episode.Episodes)
|
||||
{
|
||||
var resource = episode.ToResource();
|
||||
resource.Grabbed = true;
|
||||
|
||||
BroadcastResourceChange(ModelAction.Updated, resource);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(EpisodeDownloadedEvent message)
|
||||
{
|
||||
foreach (var episode in message.Episode.Episodes)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Updated, episode.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using NzbDrone.Api.EpisodeFiles;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Api.Series;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Api.Episodes
|
||||
{
|
||||
public class EpisodeResource : RestResource
|
||||
{
|
||||
public int SeriesId { get; set; }
|
||||
public int EpisodeFileId { get; set; }
|
||||
public int SeasonNumber { get; set; }
|
||||
public int EpisodeNumber { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string AirDate { get; set; }
|
||||
public DateTime? AirDateUtc { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public EpisodeFileResource EpisodeFile { get; set; }
|
||||
|
||||
public bool HasFile { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
public int? AbsoluteEpisodeNumber { get; set; }
|
||||
public int? SceneAbsoluteEpisodeNumber { get; set; }
|
||||
public int? SceneEpisodeNumber { get; set; }
|
||||
public int? SceneSeasonNumber { get; set; }
|
||||
public bool UnverifiedSceneNumbering { get; set; }
|
||||
public string SeriesTitle { get; set; }
|
||||
public SeriesResource Series { get; set; }
|
||||
|
||||
//Hiding this so people don't think its usable (only used to set the initial state)
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public bool Grabbed { get; set; }
|
||||
}
|
||||
|
||||
public static class EpisodeResourceMapper
|
||||
{
|
||||
public static EpisodeResource ToResource(this Episode model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new EpisodeResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
SeriesId = model.SeriesId,
|
||||
EpisodeFileId = model.EpisodeFileId,
|
||||
SeasonNumber = model.SeasonNumber,
|
||||
EpisodeNumber = model.EpisodeNumber,
|
||||
Title = model.Title,
|
||||
AirDate = model.AirDate,
|
||||
AirDateUtc = model.AirDateUtc,
|
||||
Overview = model.Overview,
|
||||
//EpisodeFile
|
||||
|
||||
HasFile = model.HasFile,
|
||||
Monitored = model.Monitored,
|
||||
AbsoluteEpisodeNumber = model.AbsoluteEpisodeNumber,
|
||||
SceneAbsoluteEpisodeNumber = model.SceneAbsoluteEpisodeNumber,
|
||||
SceneEpisodeNumber = model.SceneEpisodeNumber,
|
||||
SceneSeasonNumber = model.SceneSeasonNumber,
|
||||
UnverifiedSceneNumbering = model.UnverifiedSceneNumbering,
|
||||
SeriesTitle = model.SeriesTitle,
|
||||
//Series = model.Series.MapToResource(),
|
||||
};
|
||||
}
|
||||
|
||||
public static List<EpisodeResource> ToResource(this IEnumerable<Episode> models)
|
||||
{
|
||||
if (models == null) return null;
|
||||
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Nancy;
|
||||
using Lidarr.Http.Extensions;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
|
||||
namespace NzbDrone.Api.FileSystem
|
||||
{
|
||||
public class FileSystemModule : NzbDroneApiModule
|
||||
{
|
||||
private readonly IFileSystemLookupService _fileSystemLookupService;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IDiskScanService _diskScanService;
|
||||
|
||||
public FileSystemModule(IFileSystemLookupService fileSystemLookupService,
|
||||
IDiskProvider diskProvider,
|
||||
IDiskScanService diskScanService)
|
||||
: base("/filesystem")
|
||||
{
|
||||
_fileSystemLookupService = fileSystemLookupService;
|
||||
_diskProvider = diskProvider;
|
||||
_diskScanService = diskScanService;
|
||||
Get["/"] = x => GetContents();
|
||||
Get["/type"] = x => GetEntityType();
|
||||
Get["/mediafiles"] = x => GetMediaFiles();
|
||||
}
|
||||
|
||||
private Response GetContents()
|
||||
{
|
||||
var pathQuery = Request.Query.path;
|
||||
var includeFilesQuery = Request.Query.includeFiles;
|
||||
bool includeFiles = false;
|
||||
|
||||
if (includeFilesQuery.HasValue)
|
||||
{
|
||||
includeFiles = Convert.ToBoolean(includeFilesQuery.Value);
|
||||
}
|
||||
|
||||
return _fileSystemLookupService.LookupContents((string)pathQuery.Value, includeFiles).AsResponse();
|
||||
}
|
||||
|
||||
private Response GetEntityType()
|
||||
{
|
||||
var pathQuery = Request.Query.path;
|
||||
var path = (string)pathQuery.Value;
|
||||
|
||||
if (_diskProvider.FileExists(path))
|
||||
{
|
||||
return new { type = "file" }.AsResponse();
|
||||
}
|
||||
|
||||
//Return folder even if it doesn't exist on disk to avoid leaking anything from the UI about the underlying system
|
||||
return new { type = "folder" }.AsResponse();
|
||||
}
|
||||
|
||||
private Response GetMediaFiles()
|
||||
{
|
||||
var pathQuery = Request.Query.path;
|
||||
var path = (string)pathQuery.Value;
|
||||
|
||||
if (!_diskProvider.FolderExists(path))
|
||||
{
|
||||
return new string[0].AsResponse();
|
||||
}
|
||||
|
||||
return _diskScanService.GetAudioFiles(path).Select(f => new {
|
||||
Path = f,
|
||||
RelativePath = path.GetRelativePath(f),
|
||||
Name = Path.GetFileName(f)
|
||||
}).AsResponse();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
using NzbDrone.Core.HealthCheck;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.SignalR;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Health
|
||||
{
|
||||
public class HealthModule : LidarrRestModuleWithSignalR<HealthResource, HealthCheck>,
|
||||
IHandle<HealthCheckCompleteEvent>
|
||||
{
|
||||
private readonly IHealthCheckService _healthCheckService;
|
||||
|
||||
public HealthModule(IBroadcastSignalRMessage signalRBroadcaster, IHealthCheckService healthCheckService)
|
||||
: base(signalRBroadcaster)
|
||||
{
|
||||
_healthCheckService = healthCheckService;
|
||||
GetResourceAll = GetHealth;
|
||||
}
|
||||
|
||||
private List<HealthResource> GetHealth()
|
||||
{
|
||||
return _healthCheckService.Results().ToResource();
|
||||
}
|
||||
|
||||
public void Handle(HealthCheckCompleteEvent message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Sync);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.HealthCheck;
|
||||
|
||||
namespace NzbDrone.Api.Health
|
||||
{
|
||||
public class HealthResource : RestResource
|
||||
{
|
||||
public HealthCheckResult Type { get; set; }
|
||||
public string Message { get; set; }
|
||||
public HttpUri WikiUrl { get; set; }
|
||||
}
|
||||
|
||||
public static class HealthResourceMapper
|
||||
{
|
||||
public static HealthResource ToResource(this HealthCheck model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new HealthResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
Type = model.Type,
|
||||
Message = model.Message,
|
||||
WikiUrl = model.WikiUrl
|
||||
};
|
||||
}
|
||||
|
||||
public static List<HealthResource> ToResource(this IEnumerable<HealthCheck> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
using System;
|
||||
using Nancy;
|
||||
using NzbDrone.Api.Episodes;
|
||||
using NzbDrone.Api.Albums;
|
||||
using Lidarr.Http.Extensions;
|
||||
using NzbDrone.Api.Series;
|
||||
using NzbDrone.Api.Music;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.History;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.History
|
||||
{
|
||||
public class HistoryModule : LidarrRestModule<HistoryResource>
|
||||
{
|
||||
private readonly IHistoryService _historyService;
|
||||
private readonly IUpgradableSpecification _upgradableSpecification;
|
||||
private readonly IFailedDownloadService _failedDownloadService;
|
||||
|
||||
public HistoryModule(IHistoryService historyService,
|
||||
IUpgradableSpecification qualityUpgradableSpecification,
|
||||
IFailedDownloadService failedDownloadService)
|
||||
{
|
||||
_historyService = historyService;
|
||||
_upgradableSpecification = qualityUpgradableSpecification;
|
||||
_failedDownloadService = failedDownloadService;
|
||||
GetResourcePaged = GetHistory;
|
||||
|
||||
Post["/failed"] = x => MarkAsFailed();
|
||||
}
|
||||
|
||||
protected HistoryResource MapToResource(Core.History.History model)
|
||||
{
|
||||
var resource = model.ToResource();
|
||||
|
||||
resource.Artist = model.Artist.ToResource();
|
||||
resource.Album = model.Album.ToResource();
|
||||
|
||||
if (model.Artist != null)
|
||||
{
|
||||
resource.QualityCutoffNotMet = _upgradableSpecification.CutoffNotMet(model.Artist.Profile.Value,
|
||||
model.Artist.LanguageProfile,
|
||||
model.Quality,
|
||||
model.Language);
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
private PagingResource<HistoryResource> GetHistory(PagingResource<HistoryResource> pagingResource)
|
||||
{
|
||||
var albumId = Request.Query.AlbumId;
|
||||
|
||||
var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, Core.History.History>("date", SortDirection.Descending);
|
||||
|
||||
if (pagingResource.FilterKey == "eventType")
|
||||
{
|
||||
var filterValue = (HistoryEventType)Convert.ToInt32(pagingResource.FilterValue);
|
||||
pagingSpec.FilterExpression = v => v.EventType == filterValue;
|
||||
}
|
||||
|
||||
if (albumId.HasValue)
|
||||
{
|
||||
int i = (int)albumId;
|
||||
pagingSpec.FilterExpression = h => h.AlbumId == i;
|
||||
}
|
||||
|
||||
return ApplyToPage(_historyService.Paged, pagingSpec, MapToResource);
|
||||
}
|
||||
|
||||
private Response MarkAsFailed()
|
||||
{
|
||||
var id = (int)Request.Form.Id;
|
||||
_failedDownloadService.MarkAsFailed(id);
|
||||
return new object().AsResponse();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Api.Episodes;
|
||||
using NzbDrone.Api.Albums;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Api.Series;
|
||||
using NzbDrone.Api.Music;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Languages;
|
||||
|
||||
|
||||
namespace NzbDrone.Api.History
|
||||
{
|
||||
public class HistoryResource : RestResource
|
||||
{
|
||||
public int ArtistId { get; set; }
|
||||
public int AlbumId { get; set; }
|
||||
public string SourceTitle { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public bool QualityCutoffNotMet { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public string DownloadId { get; set; }
|
||||
public Language Language { get; set; }
|
||||
|
||||
public HistoryEventType EventType { get; set; }
|
||||
|
||||
public Dictionary<string, string> Data { get; set; }
|
||||
|
||||
public AlbumResource Album { get; set; }
|
||||
public ArtistResource Artist { get; set; }
|
||||
}
|
||||
|
||||
public static class HistoryResourceMapper
|
||||
{
|
||||
public static HistoryResource ToResource(this Core.History.History model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new HistoryResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
AlbumId = model.AlbumId,
|
||||
ArtistId = model.ArtistId,
|
||||
SourceTitle = model.SourceTitle,
|
||||
Quality = model.Quality,
|
||||
//QualityCutoffNotMet
|
||||
Date = model.Date,
|
||||
DownloadId = model.DownloadId,
|
||||
|
||||
EventType = model.EventType,
|
||||
|
||||
Data = model.Data
|
||||
//Episode
|
||||
//Series
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FluentValidation;
|
||||
using Nancy;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Exceptions;
|
||||
using NzbDrone.Core.IndexerSearch;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using Nancy.ModelBinding;
|
||||
using Lidarr.Http.Extensions;
|
||||
using NzbDrone.Common.Cache;
|
||||
using HttpStatusCode = System.Net.HttpStatusCode;
|
||||
|
||||
namespace NzbDrone.Api.Indexers
|
||||
{
|
||||
public class ReleaseModule : ReleaseModuleBase
|
||||
{
|
||||
private readonly IFetchAndParseRss _rssFetcherAndParser;
|
||||
private readonly ISearchForNzb _nzbSearchService;
|
||||
private readonly IMakeDownloadDecision _downloadDecisionMaker;
|
||||
private readonly IPrioritizeDownloadDecision _prioritizeDownloadDecision;
|
||||
private readonly IDownloadService _downloadService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
private readonly ICached<RemoteAlbum> _remoteAlbumCache;
|
||||
|
||||
public ReleaseModule(IFetchAndParseRss rssFetcherAndParser,
|
||||
ISearchForNzb nzbSearchService,
|
||||
IMakeDownloadDecision downloadDecisionMaker,
|
||||
IPrioritizeDownloadDecision prioritizeDownloadDecision,
|
||||
IDownloadService downloadService,
|
||||
ICacheManager cacheManager,
|
||||
Logger logger)
|
||||
{
|
||||
_rssFetcherAndParser = rssFetcherAndParser;
|
||||
_nzbSearchService = nzbSearchService;
|
||||
_downloadDecisionMaker = downloadDecisionMaker;
|
||||
_prioritizeDownloadDecision = prioritizeDownloadDecision;
|
||||
_downloadService = downloadService;
|
||||
_logger = logger;
|
||||
|
||||
GetResourceAll = GetReleases;
|
||||
Post["/"] = x => DownloadRelease(this.Bind<ReleaseResource>());
|
||||
|
||||
PostValidator.RuleFor(s => s.DownloadAllowed).Equal(true);
|
||||
PostValidator.RuleFor(s => s.Guid).NotEmpty();
|
||||
|
||||
_remoteAlbumCache = cacheManager.GetCache<RemoteAlbum>(GetType(), "remoteAlbums");
|
||||
}
|
||||
|
||||
private Response DownloadRelease(ReleaseResource release)
|
||||
{
|
||||
var remoteAlbum = _remoteAlbumCache.Find(release.Guid);
|
||||
|
||||
if (remoteAlbum == null)
|
||||
{
|
||||
_logger.Debug("Couldn't find requested release in cache, cache timeout probably expired.");
|
||||
|
||||
return new NotFoundResponse();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_downloadService.DownloadReport(remoteAlbum);
|
||||
}
|
||||
catch (ReleaseDownloadException ex)
|
||||
{
|
||||
_logger.Error(ex);
|
||||
throw new NzbDroneClientException(HttpStatusCode.Conflict, "Getting release from indexer failed");
|
||||
}
|
||||
|
||||
return release.AsResponse();
|
||||
}
|
||||
|
||||
private List<ReleaseResource> GetReleases()
|
||||
{
|
||||
if (Request.Query.albumId != null)
|
||||
{
|
||||
return GetAlbumReleases(Request.Query.albumId);
|
||||
}
|
||||
|
||||
return GetRss();
|
||||
}
|
||||
|
||||
private List<ReleaseResource> GetAlbumReleases(int albumId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var decisions = _nzbSearchService.AlbumSearch(albumId, true, true);
|
||||
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions);
|
||||
|
||||
return MapDecisions(prioritizedDecisions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, "Album search failed");
|
||||
}
|
||||
|
||||
return new List<ReleaseResource>();
|
||||
}
|
||||
|
||||
private List<ReleaseResource> GetRss()
|
||||
{
|
||||
var reports = _rssFetcherAndParser.Fetch();
|
||||
var decisions = _downloadDecisionMaker.GetRssDecision(reports);
|
||||
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions);
|
||||
|
||||
return MapDecisions(prioritizedDecisions);
|
||||
}
|
||||
|
||||
protected override ReleaseResource MapDecision(DownloadDecision decision, int initialWeight)
|
||||
{
|
||||
_remoteAlbumCache.Set(decision.RemoteAlbum.Release.Guid, decision.RemoteAlbum, TimeSpan.FromMinutes(30));
|
||||
return base.MapDecision(decision, initialWeight);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Indexers
|
||||
{
|
||||
public abstract class ReleaseModuleBase : LidarrRestModule<ReleaseResource>
|
||||
{
|
||||
protected virtual List<ReleaseResource> MapDecisions(IEnumerable<DownloadDecision> decisions)
|
||||
{
|
||||
var result = new List<ReleaseResource>();
|
||||
|
||||
foreach (var downloadDecision in decisions)
|
||||
{
|
||||
var release = MapDecision(downloadDecision, result.Count);
|
||||
|
||||
result.Add(release);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected virtual ReleaseResource MapDecision(DownloadDecision decision, int initialWeight)
|
||||
{
|
||||
var release = decision.ToResource();
|
||||
|
||||
release.ReleaseWeight = initialWeight;
|
||||
|
||||
if (decision.RemoteAlbum.Artist != null)
|
||||
{
|
||||
release.QualityWeight = decision.RemoteAlbum.Artist
|
||||
.Profile.Value
|
||||
.Items.FindIndex(v => v.Quality == release.Quality.Quality) * 100;
|
||||
}
|
||||
|
||||
release.QualityWeight += release.Quality.Revision.Real * 10;
|
||||
release.QualityWeight += release.Quality.Revision.Version;
|
||||
|
||||
return release;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
using Nancy;
|
||||
using Nancy.ModelBinding;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using Lidarr.Http.Extensions;
|
||||
using NLog;
|
||||
|
||||
namespace NzbDrone.Api.Indexers
|
||||
{
|
||||
class ReleasePushModule : ReleaseModuleBase
|
||||
{
|
||||
private readonly IMakeDownloadDecision _downloadDecisionMaker;
|
||||
private readonly IProcessDownloadDecisions _downloadDecisionProcessor;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public ReleasePushModule(IMakeDownloadDecision downloadDecisionMaker,
|
||||
IProcessDownloadDecisions downloadDecisionProcessor,
|
||||
Logger logger)
|
||||
{
|
||||
_downloadDecisionMaker = downloadDecisionMaker;
|
||||
_downloadDecisionProcessor = downloadDecisionProcessor;
|
||||
_logger = logger;
|
||||
|
||||
Post["/push"] = x => ProcessRelease(this.Bind<ReleaseResource>());
|
||||
|
||||
PostValidator.RuleFor(s => s.Title).NotEmpty();
|
||||
PostValidator.RuleFor(s => s.DownloadUrl).NotEmpty();
|
||||
PostValidator.RuleFor(s => s.Protocol).NotEmpty();
|
||||
PostValidator.RuleFor(s => s.PublishDate).NotEmpty();
|
||||
}
|
||||
|
||||
private Response ProcessRelease(ReleaseResource release)
|
||||
{
|
||||
_logger.Info("Release pushed: {0} - {1}", release.Title, release.DownloadUrl);
|
||||
|
||||
var info = release.ToModel();
|
||||
|
||||
info.Guid = "PUSH-" + info.DownloadUrl;
|
||||
|
||||
var decisions = _downloadDecisionMaker.GetRssDecision(new List<ReleaseInfo> { info });
|
||||
_downloadDecisionProcessor.ProcessDecisions(decisions);
|
||||
|
||||
return MapDecisions(decisions).First().AsResponse();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,158 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using System.Linq;
|
||||
|
||||
namespace NzbDrone.Api.Indexers
|
||||
{
|
||||
public class ReleaseResource : RestResource
|
||||
{
|
||||
public string Guid { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public int QualityWeight { get; set; }
|
||||
public int Age { get; set; }
|
||||
public double AgeHours { get; set; }
|
||||
public double AgeMinutes { get; set; }
|
||||
public long Size { get; set; }
|
||||
public int IndexerId { get; set; }
|
||||
public string Indexer { get; set; }
|
||||
public string ReleaseGroup { get; set; }
|
||||
public string ReleaseHash { get; set; }
|
||||
public string Title { get; set; }
|
||||
public Language Language { get; set; }
|
||||
public string ReleaseDate { get; set; }
|
||||
public string ArtistName { get; set; }
|
||||
public string AlbumTitle { get; set; }
|
||||
public bool Approved { get; set; }
|
||||
public bool TemporarilyRejected { get; set; }
|
||||
public bool Rejected { get; set; }
|
||||
public IEnumerable<string> Rejections { get; set; }
|
||||
public DateTime PublishDate { get; set; }
|
||||
public string CommentUrl { get; set; }
|
||||
public string DownloadUrl { get; set; }
|
||||
public string InfoUrl { get; set; }
|
||||
public bool DownloadAllowed { get; set; }
|
||||
public int ReleaseWeight { get; set; }
|
||||
|
||||
|
||||
public string MagnetUrl { get; set; }
|
||||
public string InfoHash { get; set; }
|
||||
public int? Seeders { get; set; }
|
||||
public int? Leechers { get; set; }
|
||||
public DownloadProtocol Protocol { get; set; }
|
||||
|
||||
|
||||
// TODO: Remove in v3
|
||||
// Used to support the original Release Push implementation
|
||||
// JsonIgnore so we don't serialize it, but can still parse it
|
||||
[JsonIgnore]
|
||||
public DownloadProtocol DownloadProtocol
|
||||
{
|
||||
get
|
||||
{
|
||||
return Protocol;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value > 0 && Protocol == 0)
|
||||
{
|
||||
Protocol = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDaily { get; set; }
|
||||
public bool IsAbsoluteNumbering { get; set; }
|
||||
public bool IsPossibleSpecialEpisode { get; set; }
|
||||
public bool Special { get; set; }
|
||||
}
|
||||
|
||||
public static class ReleaseResourceMapper
|
||||
{
|
||||
public static ReleaseResource ToResource(this DownloadDecision model)
|
||||
{
|
||||
var releaseInfo = model.RemoteAlbum.Release;
|
||||
var parsedAlbumInfo = model.RemoteAlbum.ParsedAlbumInfo;
|
||||
var remoteAlbum = model.RemoteAlbum;
|
||||
var torrentInfo = (model.RemoteAlbum.Release as TorrentInfo) ?? new TorrentInfo();
|
||||
|
||||
// TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead? (Got a huge Deja Vu, didn't we talk about this already once?)
|
||||
return new ReleaseResource
|
||||
{
|
||||
Guid = releaseInfo.Guid,
|
||||
Quality = parsedAlbumInfo.Quality,
|
||||
//QualityWeight
|
||||
Age = releaseInfo.Age,
|
||||
AgeHours = releaseInfo.AgeHours,
|
||||
AgeMinutes = releaseInfo.AgeMinutes,
|
||||
Size = releaseInfo.Size,
|
||||
IndexerId = releaseInfo.IndexerId,
|
||||
Indexer = releaseInfo.Indexer,
|
||||
ReleaseGroup = parsedAlbumInfo.ReleaseGroup,
|
||||
ReleaseHash = parsedAlbumInfo.ReleaseHash,
|
||||
Title = releaseInfo.Title,
|
||||
Language = parsedAlbumInfo.Language,
|
||||
ReleaseDate = parsedAlbumInfo.ReleaseDate,
|
||||
ArtistName = parsedAlbumInfo.ArtistName,
|
||||
AlbumTitle = parsedAlbumInfo.AlbumTitle,
|
||||
Approved = model.Approved,
|
||||
TemporarilyRejected = model.TemporarilyRejected,
|
||||
Rejected = model.Rejected,
|
||||
Rejections = model.Rejections.Select(r => r.Reason).ToList(),
|
||||
PublishDate = releaseInfo.PublishDate,
|
||||
CommentUrl = releaseInfo.CommentUrl,
|
||||
DownloadUrl = releaseInfo.DownloadUrl,
|
||||
InfoUrl = releaseInfo.InfoUrl,
|
||||
DownloadAllowed = remoteAlbum.DownloadAllowed,
|
||||
//ReleaseWeight
|
||||
|
||||
MagnetUrl = torrentInfo.MagnetUrl,
|
||||
InfoHash = torrentInfo.InfoHash,
|
||||
Seeders = torrentInfo.Seeders,
|
||||
Leechers = (torrentInfo.Peers.HasValue && torrentInfo.Seeders.HasValue) ? (torrentInfo.Peers.Value - torrentInfo.Seeders.Value) : (int?)null,
|
||||
Protocol = releaseInfo.DownloadProtocol,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public static ReleaseInfo ToModel(this ReleaseResource resource)
|
||||
{
|
||||
ReleaseInfo model;
|
||||
|
||||
if (resource.Protocol == DownloadProtocol.Torrent)
|
||||
{
|
||||
model = new TorrentInfo
|
||||
{
|
||||
MagnetUrl = resource.MagnetUrl,
|
||||
InfoHash = resource.InfoHash,
|
||||
Seeders = resource.Seeders,
|
||||
Peers = (resource.Seeders.HasValue && resource.Leechers.HasValue) ? (resource.Seeders + resource.Leechers) : null
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
model = new ReleaseInfo();
|
||||
}
|
||||
|
||||
model.Guid = resource.Guid;
|
||||
model.Title = resource.Title;
|
||||
model.Size = resource.Size;
|
||||
model.DownloadUrl = resource.DownloadUrl;
|
||||
model.InfoUrl = resource.InfoUrl;
|
||||
model.CommentUrl = resource.CommentUrl;
|
||||
model.IndexerId = resource.IndexerId;
|
||||
model.Indexer = resource.Indexer;
|
||||
model.DownloadProtocol = resource.DownloadProtocol;
|
||||
model.PublishDate = resource.PublishDate;
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Disk;
|
||||
using Nancy;
|
||||
using Nancy.Responses;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Logs
|
||||
{
|
||||
public abstract class LogFileModuleBase : LidarrRestModule<LogFileResource>
|
||||
{
|
||||
protected const string LOGFILE_ROUTE = @"/(?<filename>[-.a-zA-Z0-9]+?\.txt)";
|
||||
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IConfigFileProvider _configFileProvider;
|
||||
|
||||
public LogFileModuleBase(IDiskProvider diskProvider,
|
||||
IConfigFileProvider configFileProvider,
|
||||
string route)
|
||||
: base("log/file" + route)
|
||||
{
|
||||
_diskProvider = diskProvider;
|
||||
_configFileProvider = configFileProvider;
|
||||
GetResourceAll = GetLogFilesResponse;
|
||||
|
||||
Get[LOGFILE_ROUTE] = options => GetLogFileResponse(options.filename);
|
||||
}
|
||||
|
||||
private List<LogFileResource> GetLogFilesResponse()
|
||||
{
|
||||
var result = new List<LogFileResource>();
|
||||
|
||||
var files = GetLogFiles().ToList();
|
||||
|
||||
for (int i = 0; i < files.Count; i++)
|
||||
{
|
||||
var file = files[i];
|
||||
var filename = Path.GetFileName(file);
|
||||
|
||||
result.Add(new LogFileResource
|
||||
{
|
||||
Id = i + 1,
|
||||
Filename = filename,
|
||||
LastWriteTime = _diskProvider.FileGetLastWrite(file),
|
||||
ContentsUrl = string.Format("{0}/api/{1}/{2}", _configFileProvider.UrlBase, Resource, filename),
|
||||
DownloadUrl = string.Format("{0}/{1}/{2}", _configFileProvider.UrlBase, DownloadUrlRoot, filename)
|
||||
});
|
||||
}
|
||||
|
||||
return result.OrderByDescending(l => l.LastWriteTime).ToList();
|
||||
}
|
||||
|
||||
private Response GetLogFileResponse(string filename)
|
||||
{
|
||||
var filePath = GetLogFilePath(filename);
|
||||
|
||||
if (!_diskProvider.FileExists(filePath))
|
||||
return new NotFoundResponse();
|
||||
|
||||
var data = _diskProvider.ReadAllText(filePath);
|
||||
|
||||
return new TextResponse(data);
|
||||
}
|
||||
|
||||
protected abstract IEnumerable<string> GetLogFiles();
|
||||
protected abstract string GetLogFilePath(string filename);
|
||||
|
||||
protected abstract string DownloadUrlRoot { get; }
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
using System;
|
||||
using Lidarr.Http.REST;
|
||||
|
||||
namespace NzbDrone.Api.Logs
|
||||
{
|
||||
public class LogFileResource : RestResource
|
||||
{
|
||||
public string Filename { get; set; }
|
||||
public DateTime LastWriteTime { get; set; }
|
||||
public string ContentsUrl { get; set; }
|
||||
public string DownloadUrl { get; set; }
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
using NzbDrone.Core.Instrumentation;
|
||||
using Lidarr.Http;
|
||||
using Lidarr.Http.Mapping;
|
||||
|
||||
namespace NzbDrone.Api.Logs
|
||||
{
|
||||
public class LogModule : LidarrRestModule<LogResource>
|
||||
{
|
||||
private readonly ILogService _logService;
|
||||
|
||||
public LogModule(ILogService logService)
|
||||
{
|
||||
_logService = logService;
|
||||
GetResourcePaged = GetLogs;
|
||||
}
|
||||
|
||||
private PagingResource<LogResource> GetLogs(PagingResource<LogResource> pagingResource)
|
||||
{
|
||||
var pageSpec = pagingResource.MapToPagingSpec<LogResource, Log>();
|
||||
|
||||
if (pageSpec.SortKey == "time")
|
||||
{
|
||||
pageSpec.SortKey = "id";
|
||||
}
|
||||
|
||||
if (pagingResource.FilterKey == "level")
|
||||
{
|
||||
switch (pagingResource.FilterValue)
|
||||
{
|
||||
case "Fatal":
|
||||
pageSpec.FilterExpression = h => h.Level == "Fatal";
|
||||
break;
|
||||
case "Error":
|
||||
pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error";
|
||||
break;
|
||||
case "Warn":
|
||||
pageSpec.FilterExpression = 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";
|
||||
break;
|
||||
case "Debug":
|
||||
pageSpec.FilterExpression = 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";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ApplyToPage(_logService.Paged, pageSpec, LogResourceMapper.ToResource);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
using System;
|
||||
using Lidarr.Http.REST;
|
||||
|
||||
namespace NzbDrone.Api.Logs
|
||||
{
|
||||
public class LogResource : RestResource
|
||||
{
|
||||
public DateTime Time { get; set; }
|
||||
public string Exception { get; set; }
|
||||
public string ExceptionType { get; set; }
|
||||
public string Level { get; set; }
|
||||
public string Logger { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
|
||||
public static class LogResourceMapper
|
||||
{
|
||||
public static LogResource ToResource(this Core.Instrumentation.Log model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new LogResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
Time = model.Time,
|
||||
Exception = model.Exception,
|
||||
ExceptionType = model.ExceptionType,
|
||||
Level = model.Level,
|
||||
Logger = model.Logger,
|
||||
Message = model.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport.Manual;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.ManualImport
|
||||
{
|
||||
public class ManualImportModule : LidarrRestModule<ManualImportResource>
|
||||
{
|
||||
private readonly IManualImportService _manualImportService;
|
||||
|
||||
public ManualImportModule(IManualImportService manualImportService)
|
||||
: base("/manualimport")
|
||||
{
|
||||
_manualImportService = manualImportService;
|
||||
|
||||
GetResourceAll = GetMediaFiles;
|
||||
}
|
||||
|
||||
private List<ManualImportResource> GetMediaFiles()
|
||||
{
|
||||
var folderQuery = Request.Query.folder;
|
||||
var folder = (string)folderQuery.Value;
|
||||
|
||||
var downloadIdQuery = Request.Query.downloadId;
|
||||
var downloadId = (string)downloadIdQuery.Value;
|
||||
|
||||
return _manualImportService.GetMediaFiles(folder, downloadId).ToResource().Select(AddQualityWeight).ToList();
|
||||
}
|
||||
|
||||
private ManualImportResource AddQualityWeight(ManualImportResource item)
|
||||
{
|
||||
if (item.Quality != null)
|
||||
{
|
||||
item.QualityWeight = Quality.DefaultQualityDefinitions.Single(q => q.Quality == item.Quality.Quality).Weight;
|
||||
item.QualityWeight += item.Quality.Revision.Real * 10;
|
||||
item.QualityWeight += item.Quality.Revision.Version;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Api.Episodes;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Api.Series;
|
||||
using NzbDrone.Common.Crypto;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Api.ManualImport
|
||||
{
|
||||
public class ManualImportResource : RestResource
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public string RelativePath { get; set; }
|
||||
public string Name { get; set; }
|
||||
public long Size { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public int QualityWeight { get; set; }
|
||||
public string DownloadId { get; set; }
|
||||
public IEnumerable<Rejection> Rejections { get; set; }
|
||||
}
|
||||
|
||||
public static class ManualImportResourceMapper
|
||||
{
|
||||
public static ManualImportResource ToResource(this Core.MediaFiles.TrackImport.Manual.ManualImportItem model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new ManualImportResource
|
||||
{
|
||||
Id = HashConverter.GetHashInt31(model.Path),
|
||||
|
||||
Path = model.Path,
|
||||
RelativePath = model.RelativePath,
|
||||
Name = model.Name,
|
||||
Size = model.Size,
|
||||
Quality = model.Quality,
|
||||
//QualityWeight
|
||||
DownloadId = model.DownloadId,
|
||||
Rejections = model.Rejections
|
||||
};
|
||||
}
|
||||
|
||||
public static List<ManualImportResource> ToResource(this IEnumerable<Core.MediaFiles.TrackImport.Manual.ManualImportItem> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Nancy;
|
||||
using Lidarr.Http.REST;
|
||||
using Lidarr.Http.Extensions;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.Parser;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using Marr.Data;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Core.Music;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Music
|
||||
{
|
||||
|
||||
public class UnmappedComparer : IComparer<UnmappedFolder>
|
||||
{
|
||||
public int Compare(UnmappedFolder a, UnmappedFolder b)
|
||||
{
|
||||
return a.Name.CompareTo(b.Name);
|
||||
}
|
||||
}
|
||||
|
||||
public class MusicBulkImportModule : LidarrRestModule<ArtistResource>
|
||||
{
|
||||
private readonly ISearchForNewArtist _searchProxy;
|
||||
private readonly IRootFolderService _rootFolderService;
|
||||
private readonly IMakeImportDecision _importDecisionMaker;
|
||||
private readonly IDiskScanService _diskScanService;
|
||||
private readonly ICached<Core.Music.Artist> _mappedArtists;
|
||||
private readonly IArtistService _artistService;
|
||||
|
||||
public MusicBulkImportModule(ISearchForNewArtist searchProxy,
|
||||
IRootFolderService rootFolderService,
|
||||
IMakeImportDecision importDecisionMaker,
|
||||
IDiskScanService diskScanService,
|
||||
ICacheManager cacheManager,
|
||||
IArtistService artistService
|
||||
)
|
||||
: base("/artist/bulkimport")
|
||||
{
|
||||
_searchProxy = searchProxy;
|
||||
_rootFolderService = rootFolderService;
|
||||
_importDecisionMaker = importDecisionMaker;
|
||||
_diskScanService = diskScanService;
|
||||
_mappedArtists = cacheManager.GetCache<Artist>(GetType(), "mappedArtistsCache");
|
||||
_artistService = artistService;
|
||||
Get["/"] = x => Search();
|
||||
}
|
||||
|
||||
|
||||
private Response Search()
|
||||
{
|
||||
if (Request.Query.Id == 0)
|
||||
{
|
||||
throw new BadRequestException("Invalid Query");
|
||||
}
|
||||
|
||||
RootFolder rootFolder = _rootFolderService.Get(Request.Query.Id);
|
||||
|
||||
var unmapped = rootFolder.UnmappedFolders.OrderBy(f => f.Name).ToList();
|
||||
|
||||
var paged = unmapped;
|
||||
|
||||
var mapped = paged.Select(page =>
|
||||
{
|
||||
Artist m = null;
|
||||
|
||||
var mappedArtist = _mappedArtists.Find(page.Name);
|
||||
|
||||
if (mappedArtist != null)
|
||||
{
|
||||
return mappedArtist;
|
||||
}
|
||||
|
||||
var files = _diskScanService.GetAudioFiles(page.Path);
|
||||
|
||||
// Check for music files in directory
|
||||
if (files.Count() == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var parsedTitle = Parser.ParseMusicPath(files.FirstOrDefault());
|
||||
if (parsedTitle == null || parsedTitle.ArtistTitle == null)
|
||||
{
|
||||
m = new Artist
|
||||
{
|
||||
Name = page.Name.Replace(".", " ").Replace("-", " "),
|
||||
Path = page.Path,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
m = new Artist
|
||||
{
|
||||
Name = parsedTitle.ArtistTitle,
|
||||
Path = page.Path
|
||||
};
|
||||
}
|
||||
|
||||
var searchResults = _searchProxy.SearchForNewArtist(m.Name);
|
||||
|
||||
if (searchResults == null || searchResults.Count == 0)
|
||||
{
|
||||
return null;
|
||||
};
|
||||
|
||||
mappedArtist = searchResults.First();
|
||||
|
||||
if (mappedArtist != null)
|
||||
{
|
||||
mappedArtist.Monitored = true;
|
||||
mappedArtist.Path = page.Path;
|
||||
|
||||
_mappedArtists.Set(page.Name, mappedArtist, TimeSpan.FromDays(2));
|
||||
|
||||
return mappedArtist;
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
var mapping = MapToResource(mapped.Where(m => m != null)).ToList().AsResponse();
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
||||
private static IEnumerable<ArtistResource> MapToResource(IEnumerable<Artist> artists)
|
||||
{
|
||||
foreach (var currentArtist in artists)
|
||||
{
|
||||
var resource = currentArtist.ToResource();
|
||||
var poster = currentArtist.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster);
|
||||
if (poster != null)
|
||||
{
|
||||
resource.RemotePoster = poster.Url;
|
||||
}
|
||||
|
||||
yield return resource;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Nancy;
|
||||
using Lidarr.Http.Extensions;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Api.Music
|
||||
{
|
||||
public class ArtistEditorModule : NzbDroneApiModule
|
||||
{
|
||||
private readonly IArtistService _artistService;
|
||||
|
||||
public ArtistEditorModule(IArtistService seriesService)
|
||||
: base("/artist/editor")
|
||||
{
|
||||
_artistService = seriesService;
|
||||
Put["/"] = artist => SaveAll();
|
||||
}
|
||||
|
||||
private Response SaveAll()
|
||||
{
|
||||
var resources = Request.Body.FromJson<List<ArtistResource>>();
|
||||
|
||||
var artist = resources.Select(artistResource => artistResource.ToModel(_artistService.GetArtist(artistResource.Id))).ToList();
|
||||
|
||||
return _artistService.UpdateArtists(artist)
|
||||
.ToResource()
|
||||
.AsResponse(HttpStatusCode.Accepted);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
using Nancy;
|
||||
using Lidarr.Http.Extensions;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Music
|
||||
{
|
||||
public class ArtistLookupModule : LidarrRestModule<ArtistResource>
|
||||
{
|
||||
private readonly ISearchForNewArtist _searchProxy;
|
||||
|
||||
public ArtistLookupModule(ISearchForNewArtist searchProxy)
|
||||
: base("/artist/lookup")
|
||||
{
|
||||
_searchProxy = searchProxy;
|
||||
Get["/"] = x => Search();
|
||||
}
|
||||
|
||||
|
||||
private Response Search()
|
||||
{
|
||||
var iTunesResults = _searchProxy.SearchForNewArtist((string)Request.Query.term);
|
||||
return MapToResource(iTunesResults).AsResponse();
|
||||
}
|
||||
|
||||
|
||||
private static IEnumerable<ArtistResource> MapToResource(IEnumerable<Core.Music.Artist> artists)
|
||||
{
|
||||
foreach (var currentArtist in artists)
|
||||
{
|
||||
var resource = currentArtist.ToResource();
|
||||
var poster = currentArtist.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster);
|
||||
if (poster != null)
|
||||
{
|
||||
resource.RemotePoster = poster.Url;
|
||||
}
|
||||
|
||||
yield return resource;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,226 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.Music.Events;
|
||||
using NzbDrone.Core.ArtistStats;
|
||||
using NzbDrone.Core.Validation;
|
||||
using NzbDrone.Core.Validation.Paths;
|
||||
using NzbDrone.SignalR;
|
||||
using Lidarr.Http;
|
||||
using Lidarr.Http.Mapping;
|
||||
|
||||
namespace NzbDrone.Api.Music
|
||||
{
|
||||
public class ArtistModule : LidarrRestModuleWithSignalR<ArtistResource, Artist>,
|
||||
IHandle<TrackImportedEvent>,
|
||||
IHandle<TrackFileDeletedEvent>,
|
||||
IHandle<ArtistUpdatedEvent>,
|
||||
IHandle<ArtistEditedEvent>,
|
||||
IHandle<ArtistDeletedEvent>,
|
||||
IHandle<ArtistRenamedEvent>
|
||||
//IHandle<MediaCoversUpdatedEvent>
|
||||
{
|
||||
private readonly IArtistService _artistService;
|
||||
private readonly IAddArtistService _addArtistService;
|
||||
private readonly IArtistStatisticsService _artistStatisticsService;
|
||||
private readonly IMapCoversToLocal _coverMapper;
|
||||
|
||||
public ArtistModule(IBroadcastSignalRMessage signalRBroadcaster,
|
||||
IArtistService artistService,
|
||||
IAddArtistService addArtistService,
|
||||
IArtistStatisticsService artistStatisticsService,
|
||||
IMapCoversToLocal coverMapper,
|
||||
RootFolderValidator rootFolderValidator,
|
||||
ArtistPathValidator seriesPathValidator,
|
||||
ArtistExistsValidator artistExistsValidator,
|
||||
SeriesAncestorValidator seriesAncestorValidator,
|
||||
ProfileExistsValidator profileExistsValidator,
|
||||
LanguageProfileExistsValidator languageProfileExistsValidator
|
||||
)
|
||||
: base(signalRBroadcaster)
|
||||
{
|
||||
_artistService = artistService;
|
||||
_addArtistService = addArtistService;
|
||||
_artistStatisticsService = artistStatisticsService;
|
||||
|
||||
_coverMapper = coverMapper;
|
||||
|
||||
GetResourceAll = AllArtist;
|
||||
GetResourceById = GetArtist;
|
||||
CreateResource = AddArtist;
|
||||
UpdateResource = UpdatArtist;
|
||||
DeleteResource = DeleteArtist;
|
||||
|
||||
SharedValidator.RuleFor(s => s.ProfileId).ValidId();
|
||||
SharedValidator.RuleFor(s => s.LanguageProfileId);
|
||||
|
||||
SharedValidator.RuleFor(s => s.Path)
|
||||
.Cascade(CascadeMode.StopOnFirstFailure)
|
||||
.IsValidPath()
|
||||
.SetValidator(rootFolderValidator)
|
||||
.SetValidator(seriesPathValidator)
|
||||
.SetValidator(seriesAncestorValidator)
|
||||
.When(s => !s.Path.IsNullOrWhiteSpace());
|
||||
|
||||
SharedValidator.RuleFor(s => s.ProfileId).SetValidator(profileExistsValidator);
|
||||
SharedValidator.RuleFor(s => s.LanguageProfileId).SetValidator(languageProfileExistsValidator);
|
||||
|
||||
PostValidator.RuleFor(s => s.Path).IsValidPath().When(s => s.RootFolderPath.IsNullOrWhiteSpace());
|
||||
PostValidator.RuleFor(s => s.RootFolderPath).IsValidPath().When(s => s.Path.IsNullOrWhiteSpace());
|
||||
PostValidator.RuleFor(s => s.ForeignArtistId).NotEqual("").SetValidator(artistExistsValidator);
|
||||
|
||||
PutValidator.RuleFor(s => s.Path).IsValidPath();
|
||||
}
|
||||
|
||||
private ArtistResource GetArtist(int id)
|
||||
{
|
||||
var artist = _artistService.GetArtist(id);
|
||||
return MapToResource(artist);
|
||||
}
|
||||
|
||||
private ArtistResource MapToResource(Artist artist)
|
||||
{
|
||||
if (artist == null) return null;
|
||||
|
||||
var resource = artist.ToResource();
|
||||
MapCoversToLocal(resource);
|
||||
FetchAndLinkArtistStatistics(resource);
|
||||
//PopulateAlternateTitles(resource);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
private List<ArtistResource> AllArtist()
|
||||
{
|
||||
var artistStats = _artistStatisticsService.ArtistStatistics();
|
||||
var artistResources = _artistService.GetAllArtists().ToResource();
|
||||
|
||||
MapCoversToLocal(artistResources.ToArray());
|
||||
LinkArtistStatistics(artistResources, artistStats);
|
||||
//PopulateAlternateTitles(seriesResources);
|
||||
|
||||
return artistResources;
|
||||
}
|
||||
|
||||
private int AddArtist(ArtistResource artistResource)
|
||||
{
|
||||
var model = artistResource.ToModel();
|
||||
|
||||
return _addArtistService.AddArtist(model).Id;
|
||||
}
|
||||
|
||||
private void UpdatArtist(ArtistResource artistResource)
|
||||
{
|
||||
var model = artistResource.ToModel(_artistService.GetArtist(artistResource.Id));
|
||||
|
||||
_artistService.UpdateArtist(model);
|
||||
|
||||
BroadcastResourceChange(ModelAction.Updated, artistResource.Id);
|
||||
}
|
||||
|
||||
private void DeleteArtist(int id)
|
||||
{
|
||||
var deleteFiles = false;
|
||||
var deleteFilesQuery = Request.Query.deleteFiles;
|
||||
|
||||
if (deleteFilesQuery.HasValue)
|
||||
{
|
||||
deleteFiles = Convert.ToBoolean(deleteFilesQuery.Value);
|
||||
}
|
||||
|
||||
_artistService.DeleteArtist(id, deleteFiles);
|
||||
}
|
||||
|
||||
private void MapCoversToLocal(params ArtistResource[] artists)
|
||||
{
|
||||
foreach (var artistResource in artists)
|
||||
{
|
||||
_coverMapper.ConvertToLocalUrls(artistResource.Id, artistResource.Images);
|
||||
}
|
||||
}
|
||||
|
||||
private void FetchAndLinkArtistStatistics(ArtistResource resource)
|
||||
{
|
||||
LinkArtistStatistics(resource, _artistStatisticsService.ArtistStatistics(resource.Id));
|
||||
}
|
||||
|
||||
|
||||
private void LinkArtistStatistics(List<ArtistResource> resources, List<ArtistStatistics> artistStatistics)
|
||||
{
|
||||
var dictArtistStats = artistStatistics.ToDictionary(v => v.ArtistId);
|
||||
|
||||
foreach (var artist in resources)
|
||||
{
|
||||
var stats = dictArtistStats.GetValueOrDefault(artist.Id);
|
||||
if (stats == null) continue;
|
||||
|
||||
LinkArtistStatistics(artist, stats);
|
||||
}
|
||||
}
|
||||
|
||||
private void LinkArtistStatistics(ArtistResource resource, ArtistStatistics artistStatistics)
|
||||
{
|
||||
resource.TotalTrackCount = artistStatistics.TotalTrackCount;
|
||||
resource.TrackCount = artistStatistics.TrackCount;
|
||||
resource.TrackFileCount = artistStatistics.TrackFileCount;
|
||||
resource.SizeOnDisk = artistStatistics.SizeOnDisk;
|
||||
resource.AlbumCount = artistStatistics.AlbumCount;
|
||||
|
||||
//if (artistStatistics.AlbumStatistics != null)
|
||||
//{
|
||||
// var dictSeasonStats = artistStatistics.SeasonStatistics.ToDictionary(v => v.SeasonNumber);
|
||||
|
||||
// foreach (var album in resource.Albums)
|
||||
// {
|
||||
// album.Statistics = dictSeasonStats.GetValueOrDefault(album.Id).ToResource();
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
public void Handle(TrackImportedEvent message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Updated, message.ImportedTrack.ArtistId);
|
||||
}
|
||||
|
||||
public void Handle(TrackFileDeletedEvent message)
|
||||
{
|
||||
if (message.Reason == DeleteMediaFileReason.Upgrade) return;
|
||||
|
||||
BroadcastResourceChange(ModelAction.Updated, message.TrackFile.ArtistId);
|
||||
}
|
||||
|
||||
public void Handle(ArtistUpdatedEvent message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Updated, message.Artist.Id);
|
||||
}
|
||||
|
||||
public void Handle(ArtistEditedEvent message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Updated, message.Artist.Id);
|
||||
}
|
||||
|
||||
public void Handle(ArtistDeletedEvent message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Deleted, message.Artist.ToResource());
|
||||
}
|
||||
|
||||
public void Handle(ArtistRenamedEvent message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Updated, message.Artist.Id);
|
||||
}
|
||||
|
||||
//public void Handle(MediaCoversUpdatedEvent message)
|
||||
//{
|
||||
// BroadcastResourceChange(ModelAction.Updated, message.Artist.Id);
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
@ -1,189 +0,0 @@
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Api.Albums;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.Music;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Api.Music
|
||||
{
|
||||
public class ArtistResource : RestResource
|
||||
{
|
||||
public ArtistResource()
|
||||
{
|
||||
Monitored = true;
|
||||
}
|
||||
|
||||
|
||||
//View Only
|
||||
public string Name { get; set; }
|
||||
public string ForeignArtistId { get; set; }
|
||||
public string MBId { get; set; }
|
||||
public int TADBId { get; set; }
|
||||
public int DiscogsId { get; set; }
|
||||
public string AllMusicId { get; set; }
|
||||
public string Overview { get; set; }
|
||||
|
||||
public int? AlbumCount{ get; set; }
|
||||
public int? TotalTrackCount { get; set; }
|
||||
public int? TrackCount { get; set; }
|
||||
public int? TrackFileCount { get; set; }
|
||||
public long? SizeOnDisk { get; set; }
|
||||
//public SeriesStatusType Status { get; set; }
|
||||
|
||||
public List<MediaCover> Images { get; set; }
|
||||
public List<Member> Members { get; set; }
|
||||
|
||||
public string RemotePoster { get; set; }
|
||||
public List<AlbumResource> Albums { get; set; }
|
||||
|
||||
|
||||
//View & Edit
|
||||
public string Path { get; set; }
|
||||
public int ProfileId { get; set; }
|
||||
public int LanguageProfileId { get; set; }
|
||||
|
||||
//Editing Only
|
||||
public bool AlbumFolder { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
|
||||
public string RootFolderPath { get; set; }
|
||||
//public string Certification { get; set; }
|
||||
public List<string> Genres { get; set; }
|
||||
public string CleanName { get; set; }
|
||||
public string SortName { get; set; }
|
||||
public HashSet<int> Tags { get; set; }
|
||||
public DateTime Added { get; set; }
|
||||
public AddArtistOptions AddOptions { get; set; }
|
||||
public Ratings Ratings { get; set; }
|
||||
public string NameSlug { get; set; }
|
||||
}
|
||||
|
||||
public static class ArtistResourceMapper
|
||||
{
|
||||
public static ArtistResource ToResource(this Core.Music.Artist model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new ArtistResource
|
||||
{
|
||||
Id = model.Id,
|
||||
MBId = model.MBId,
|
||||
TADBId = model.TADBId,
|
||||
DiscogsId = model.DiscogsId,
|
||||
AllMusicId = model.AMId,
|
||||
Name = model.Name,
|
||||
CleanName = model.CleanName,
|
||||
|
||||
//AlternateTitles
|
||||
SortName = model.SortName,
|
||||
|
||||
//TotalTrackCount
|
||||
//TrackCount
|
||||
//TrackFileCount
|
||||
//SizeOnDisk
|
||||
//Status = resource.Status,
|
||||
Overview = model.Overview,
|
||||
//NextAiring
|
||||
//PreviousAiring
|
||||
//Network = resource.Network,
|
||||
//AirTime = resource.AirTime,
|
||||
Images = model.Images,
|
||||
Members = model.Members,
|
||||
//Albums = model.Albums.ToResource(),
|
||||
//Year = resource.Year,
|
||||
|
||||
Path = model.Path,
|
||||
ProfileId = model.ProfileId,
|
||||
LanguageProfileId = model.LanguageProfileId,
|
||||
|
||||
Monitored = model.Monitored,
|
||||
AlbumFolder = model.AlbumFolder,
|
||||
|
||||
//UseSceneNumbering = resource.UseSceneNumbering,
|
||||
//Runtime = resource.Runtime,
|
||||
//TvdbId = resource.TvdbId,
|
||||
//TvRageId = resource.TvRageId,
|
||||
//TvMazeId = resource.TvMazeId,
|
||||
//FirstAired = resource.FirstAired,
|
||||
//LastInfoSync = resource.LastInfoSync,
|
||||
//SeriesType = resource.SeriesType,
|
||||
ForeignArtistId = model.ForeignArtistId,
|
||||
NameSlug = model.NameSlug,
|
||||
|
||||
RootFolderPath = model.RootFolderPath,
|
||||
Genres = model.Genres,
|
||||
Tags = model.Tags,
|
||||
Added = model.Added,
|
||||
AddOptions = model.AddOptions,
|
||||
Ratings = model.Ratings,
|
||||
};
|
||||
}
|
||||
|
||||
public static Core.Music.Artist ToModel(this ArtistResource resource)
|
||||
{
|
||||
if (resource == null) return null;
|
||||
|
||||
return new Core.Music.Artist
|
||||
{
|
||||
Id = resource.Id,
|
||||
|
||||
Name = resource.Name,
|
||||
CleanName = resource.CleanName,
|
||||
//AlternateTitles
|
||||
SortName = resource.SortName,
|
||||
MBId = resource.MBId,
|
||||
TADBId = resource.TADBId,
|
||||
DiscogsId = resource.DiscogsId,
|
||||
AMId = resource.AllMusicId, //TODO change model and DB to AllMusic instead of AM
|
||||
//TotalEpisodeCount
|
||||
//TrackCount
|
||||
//TrackFileCount
|
||||
//SizeOnDisk
|
||||
//Status = resource.Status,
|
||||
Overview = resource.Overview,
|
||||
//NextAiring
|
||||
//PreviousAiring
|
||||
//Network = resource.Network,
|
||||
//AirTime = resource.AirTime,
|
||||
Images = resource.Images,
|
||||
Members = resource.Members,
|
||||
//Albums = resource.Albums.ToModel(),
|
||||
//Year = resource.Year,
|
||||
|
||||
Path = resource.Path,
|
||||
ProfileId = resource.ProfileId,
|
||||
LanguageProfileId = resource.LanguageProfileId,
|
||||
AlbumFolder = resource.AlbumFolder,
|
||||
|
||||
Monitored = resource.Monitored,
|
||||
//LastInfoSync = resource.LastInfoSync,
|
||||
ForeignArtistId = resource.ForeignArtistId,
|
||||
NameSlug = resource.NameSlug,
|
||||
|
||||
RootFolderPath = resource.RootFolderPath,
|
||||
Genres = resource.Genres,
|
||||
Tags = resource.Tags,
|
||||
Added = resource.Added,
|
||||
AddOptions = resource.AddOptions,
|
||||
Ratings = resource.Ratings
|
||||
};
|
||||
}
|
||||
|
||||
public static Core.Music.Artist ToModel(this ArtistResource resource, Core.Music.Artist artist)
|
||||
{
|
||||
var updatedArtist = resource.ToModel();
|
||||
|
||||
artist.ApplyChanges(updatedArtist);
|
||||
|
||||
return artist;
|
||||
}
|
||||
|
||||
public static List<ArtistResource> ToResource(this IEnumerable<Core.Music.Artist> artist)
|
||||
{
|
||||
return artist.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Nancy;
|
||||
using Nancy.Extensions;
|
||||
using Lidarr.Http.Extensions;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Api.Music
|
||||
{
|
||||
public class ListImportModule : NzbDroneApiModule
|
||||
{
|
||||
private readonly IAddArtistService _artistService;
|
||||
|
||||
public ListImportModule(IAddArtistService artistService)
|
||||
: base("/artist/import")
|
||||
{
|
||||
_artistService = artistService;
|
||||
Put["/"] = Artist => SaveAll();
|
||||
}
|
||||
|
||||
private Response SaveAll()
|
||||
{
|
||||
var resources = Request.Body.FromJson<List<ArtistResource>>();
|
||||
|
||||
var Artists = resources.Select(ArtistResource => (ArtistResource.ToModel())).Where(m => m != null).DistinctBy(m => m.ForeignArtistId).ToList();
|
||||
|
||||
return _artistService.AddArtists(Artists).ToResource().AsResponse(HttpStatusCode.Accepted);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
using NzbDrone.Api.Albums;
|
||||
using NzbDrone.Api.Music;
|
||||
using NzbDrone.Core.Parser;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Parse
|
||||
{
|
||||
public class ParseModule : LidarrRestModule<ParseResource>
|
||||
{
|
||||
private readonly IParsingService _parsingService;
|
||||
|
||||
public ParseModule(IParsingService parsingService)
|
||||
{
|
||||
_parsingService = parsingService;
|
||||
|
||||
GetResourceSingle = Parse;
|
||||
}
|
||||
|
||||
private ParseResource Parse()
|
||||
{
|
||||
var title = Request.Query.Title.Value as string;
|
||||
var parsedAlbumInfo = Parser.ParseAlbumTitle(title);
|
||||
|
||||
if (parsedAlbumInfo == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var remoteAlbum = _parsingService.Map(parsedAlbumInfo);
|
||||
|
||||
if (remoteAlbum != null)
|
||||
{
|
||||
return new ParseResource
|
||||
{
|
||||
Title = title,
|
||||
ParsedAlbumInfo = remoteAlbum.ParsedAlbumInfo,
|
||||
Artist = remoteAlbum.Artist.ToResource(),
|
||||
Albums = remoteAlbum.Albums.ToResource()
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ParseResource
|
||||
{
|
||||
Title = title,
|
||||
ParsedAlbumInfo = parsedAlbumInfo
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Api.Music;
|
||||
using NzbDrone.Api.Albums;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Api.Parse
|
||||
{
|
||||
public class ParseResource : RestResource
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public ParsedAlbumInfo ParsedAlbumInfo { get; set; }
|
||||
public ArtistResource Artist { get; set; }
|
||||
public List<AlbumResource> Albums { get; set; }
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using FluentValidation;
|
||||
using FluentValidation.Results;
|
||||
using Lidarr.Http.REST;
|
||||
using Lidarr.Http.Validation;
|
||||
using NzbDrone.Core.Profiles.Delay;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Profiles.Delay
|
||||
{
|
||||
public class DelayProfileModule : LidarrRestModule<DelayProfileResource>
|
||||
{
|
||||
private readonly IDelayProfileService _delayProfileService;
|
||||
|
||||
public DelayProfileModule(IDelayProfileService delayProfileService, DelayProfileTagInUseValidator tagInUseValidator)
|
||||
{
|
||||
_delayProfileService = delayProfileService;
|
||||
|
||||
GetResourceAll = GetAll;
|
||||
GetResourceById = GetById;
|
||||
UpdateResource = Update;
|
||||
CreateResource = Create;
|
||||
DeleteResource = DeleteProfile;
|
||||
|
||||
SharedValidator.RuleFor(d => d.Tags).NotEmpty().When(d => d.Id != 1);
|
||||
SharedValidator.RuleFor(d => d.Tags).EmptyCollection<DelayProfileResource, int>().When(d => d.Id == 1);
|
||||
SharedValidator.RuleFor(d => d.Tags).SetValidator(tagInUseValidator);
|
||||
SharedValidator.RuleFor(d => d.UsenetDelay).GreaterThanOrEqualTo(0);
|
||||
SharedValidator.RuleFor(d => d.TorrentDelay).GreaterThanOrEqualTo(0);
|
||||
|
||||
SharedValidator.Custom(delayProfile =>
|
||||
{
|
||||
if (!delayProfile.EnableUsenet && !delayProfile.EnableTorrent)
|
||||
{
|
||||
return new ValidationFailure("", "Either Usenet or Torrent should be enabled");
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private int Create(DelayProfileResource resource)
|
||||
{
|
||||
var model = resource.ToModel();
|
||||
model = _delayProfileService.Add(model);
|
||||
|
||||
return model.Id;
|
||||
}
|
||||
|
||||
private void DeleteProfile(int id)
|
||||
{
|
||||
if (id == 1)
|
||||
{
|
||||
throw new MethodNotAllowedException("Cannot delete global delay profile");
|
||||
}
|
||||
|
||||
_delayProfileService.Delete(id);
|
||||
}
|
||||
|
||||
private void Update(DelayProfileResource resource)
|
||||
{
|
||||
var model = resource.ToModel();
|
||||
_delayProfileService.Update(model);
|
||||
}
|
||||
|
||||
private DelayProfileResource GetById(int id)
|
||||
{
|
||||
return _delayProfileService.Get(id).ToResource();
|
||||
}
|
||||
|
||||
private List<DelayProfileResource> GetAll()
|
||||
{
|
||||
return _delayProfileService.All().ToResource();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Profiles.Delay;
|
||||
|
||||
namespace NzbDrone.Api.Profiles.Delay
|
||||
{
|
||||
public class DelayProfileResource : RestResource
|
||||
{
|
||||
public bool EnableUsenet { get; set; }
|
||||
public bool EnableTorrent { get; set; }
|
||||
public DownloadProtocol PreferredProtocol { get; set; }
|
||||
public int UsenetDelay { get; set; }
|
||||
public int TorrentDelay { get; set; }
|
||||
public int Order { get; set; }
|
||||
public HashSet<int> Tags { get; set; }
|
||||
}
|
||||
|
||||
public static class DelayProfileResourceMapper
|
||||
{
|
||||
public static DelayProfileResource ToResource(this DelayProfile model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new DelayProfileResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
EnableUsenet = model.EnableUsenet,
|
||||
EnableTorrent = model.EnableTorrent,
|
||||
PreferredProtocol = model.PreferredProtocol,
|
||||
UsenetDelay = model.UsenetDelay,
|
||||
TorrentDelay = model.TorrentDelay,
|
||||
Order = model.Order,
|
||||
Tags = new HashSet<int>(model.Tags)
|
||||
};
|
||||
}
|
||||
|
||||
public static DelayProfile ToModel(this DelayProfileResource resource)
|
||||
{
|
||||
if (resource == null) return null;
|
||||
|
||||
return new DelayProfile
|
||||
{
|
||||
Id = resource.Id,
|
||||
|
||||
EnableUsenet = resource.EnableUsenet,
|
||||
EnableTorrent = resource.EnableTorrent,
|
||||
PreferredProtocol = resource.PreferredProtocol,
|
||||
UsenetDelay = resource.UsenetDelay,
|
||||
TorrentDelay = resource.TorrentDelay,
|
||||
Order = resource.Order,
|
||||
Tags = new HashSet<int>(resource.Tags)
|
||||
};
|
||||
}
|
||||
|
||||
public static List<DelayProfileResource> ToResource(this IEnumerable<DelayProfile> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Languages;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Profiles.Languages
|
||||
{
|
||||
public class LanguageModule : LidarrRestModule<LanguageResource>
|
||||
{
|
||||
public LanguageModule()
|
||||
{
|
||||
GetResourceAll = GetAll;
|
||||
GetResourceById = GetById;
|
||||
}
|
||||
|
||||
private LanguageResource GetById(int id)
|
||||
{
|
||||
var language = (Language)id;
|
||||
|
||||
return new LanguageResource
|
||||
{
|
||||
Id = (int)language,
|
||||
Name = language.ToString()
|
||||
};
|
||||
}
|
||||
|
||||
private List<LanguageResource> GetAll()
|
||||
{
|
||||
return ((Language[])Enum.GetValues(typeof (Language)))
|
||||
.Select(l => new LanguageResource
|
||||
{
|
||||
Id = (int) l,
|
||||
Name = l.ToString()
|
||||
})
|
||||
.OrderBy(l => l.Name)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using Lidarr.Http.REST;
|
||||
|
||||
namespace NzbDrone.Api.Profiles.Languages
|
||||
{
|
||||
public class LanguageResource : RestResource
|
||||
{
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)]
|
||||
public new int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string NameLower => Name.ToLowerInvariant();
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Validation;
|
||||
using Lidarr.Http;
|
||||
using Lidarr.Http.Mapping;
|
||||
|
||||
namespace NzbDrone.Api.Profiles
|
||||
{
|
||||
public class ProfileModule : LidarrRestModule<ProfileResource>
|
||||
{
|
||||
private readonly IProfileService _profileService;
|
||||
|
||||
public ProfileModule(IProfileService profileService)
|
||||
{
|
||||
_profileService = profileService;
|
||||
SharedValidator.RuleFor(c => c.Name).NotEmpty();
|
||||
SharedValidator.RuleFor(c => c.Cutoff).NotNull();
|
||||
SharedValidator.RuleFor(c => c.Items).MustHaveAllowedQuality();
|
||||
|
||||
GetResourceAll = GetAll;
|
||||
GetResourceById = GetById;
|
||||
UpdateResource = Update;
|
||||
CreateResource = Create;
|
||||
DeleteResource = DeleteProfile;
|
||||
}
|
||||
|
||||
private int Create(ProfileResource resource)
|
||||
{
|
||||
var model = resource.ToModel();
|
||||
|
||||
return _profileService.Add(model).Id;
|
||||
}
|
||||
|
||||
private void DeleteProfile(int id)
|
||||
{
|
||||
_profileService.Delete(id);
|
||||
}
|
||||
|
||||
private void Update(ProfileResource resource)
|
||||
{
|
||||
var model = resource.ToModel();
|
||||
|
||||
_profileService.Update(model);
|
||||
}
|
||||
|
||||
private ProfileResource GetById(int id)
|
||||
{
|
||||
return _profileService.Get(id).ToResource();
|
||||
}
|
||||
|
||||
private List<ProfileResource> GetAll()
|
||||
{
|
||||
return _profileService.All().ToResource();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Api.Profiles
|
||||
{
|
||||
public class ProfileResource : RestResource
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public Quality Cutoff { get; set; }
|
||||
public List<ProfileQualityItemResource> Items { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileQualityItemResource : RestResource
|
||||
{
|
||||
public Quality Quality { get; set; }
|
||||
public bool Allowed { get; set; }
|
||||
}
|
||||
|
||||
public static class ProfileResourceMapper
|
||||
{
|
||||
public static ProfileResource ToResource(this Profile model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new ProfileResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
Name = model.Name,
|
||||
Cutoff = model.Cutoff,
|
||||
Items = model.Items.ConvertAll(ToResource)
|
||||
};
|
||||
}
|
||||
|
||||
public static ProfileQualityItemResource ToResource(this ProfileQualityItem model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new ProfileQualityItemResource
|
||||
{
|
||||
Quality = model.Quality,
|
||||
Allowed = model.Allowed
|
||||
};
|
||||
}
|
||||
|
||||
public static Profile ToModel(this ProfileResource resource)
|
||||
{
|
||||
if (resource == null) return null;
|
||||
|
||||
return new Profile
|
||||
{
|
||||
Id = resource.Id,
|
||||
|
||||
Name = resource.Name,
|
||||
Cutoff = (Quality)resource.Cutoff.Id,
|
||||
Items = resource.Items.ConvertAll(ToModel)
|
||||
};
|
||||
}
|
||||
|
||||
public static ProfileQualityItem ToModel(this ProfileQualityItemResource resource)
|
||||
{
|
||||
if (resource == null) return null;
|
||||
|
||||
return new ProfileQualityItem
|
||||
{
|
||||
Quality = (Quality)resource.Quality.Id,
|
||||
Allowed = resource.Allowed
|
||||
};
|
||||
}
|
||||
|
||||
public static List<ProfileResource> ToResource(this IEnumerable<Profile> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using Lidarr.Http;
|
||||
using Lidarr.Http.Mapping;
|
||||
|
||||
namespace NzbDrone.Api.Profiles
|
||||
{
|
||||
public class ProfileSchemaModule : LidarrRestModule<ProfileResource>
|
||||
{
|
||||
private readonly IQualityDefinitionService _qualityDefinitionService;
|
||||
|
||||
public ProfileSchemaModule(IQualityDefinitionService qualityDefinitionService)
|
||||
: base("/profile/schema")
|
||||
{
|
||||
_qualityDefinitionService = qualityDefinitionService;
|
||||
|
||||
GetResourceAll = GetAll;
|
||||
}
|
||||
|
||||
private List<ProfileResource> GetAll()
|
||||
{
|
||||
var items = _qualityDefinitionService.All()
|
||||
.OrderBy(v => v.Weight)
|
||||
.Select(v => new ProfileQualityItem { Quality = v.Quality, Allowed = false })
|
||||
.ToList();
|
||||
|
||||
var profile = new Profile();
|
||||
profile.Cutoff = Quality.Unknown;
|
||||
profile.Items = items;
|
||||
|
||||
return new List<ProfileResource> { profile.ToResource() };
|
||||
}
|
||||
}
|
||||
}
|
@ -1,228 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentValidation;
|
||||
using FluentValidation.Results;
|
||||
using Nancy;
|
||||
using Lidarr.Http.ClientSchema;
|
||||
using Lidarr.Http.Extensions;
|
||||
using NzbDrone.Common.Reflection;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation;
|
||||
using Newtonsoft.Json;
|
||||
using Lidarr.Http;
|
||||
using Lidarr.Http.Mapping;
|
||||
|
||||
namespace NzbDrone.Api
|
||||
{
|
||||
public abstract class ProviderModuleBase<TProviderResource, TProvider, TProviderDefinition> : LidarrRestModule<TProviderResource>
|
||||
where TProviderDefinition : ProviderDefinition, new()
|
||||
where TProvider : IProvider
|
||||
where TProviderResource : ProviderResource, new()
|
||||
{
|
||||
private readonly IProviderFactory<TProvider, TProviderDefinition> _providerFactory;
|
||||
|
||||
protected ProviderModuleBase(IProviderFactory<TProvider, TProviderDefinition> providerFactory, string resource)
|
||||
: base(resource)
|
||||
{
|
||||
_providerFactory = providerFactory;
|
||||
|
||||
Get["schema"] = x => GetTemplates();
|
||||
Post["test"] = x => Test(ReadResourceFromRequest(true));
|
||||
Post["action/{action}"] = x => RequestAction(x.action, ReadResourceFromRequest(true));
|
||||
|
||||
GetResourceAll = GetAll;
|
||||
GetResourceById = GetProviderById;
|
||||
CreateResource = CreateProvider;
|
||||
UpdateResource = UpdateProvider;
|
||||
DeleteResource = DeleteProvider;
|
||||
|
||||
SharedValidator.RuleFor(c => c.Name).NotEmpty();
|
||||
SharedValidator.RuleFor(c => c.Name).Must((v,c) => !_providerFactory.All().Any(p => p.Name == c && p.Id != v.Id)).WithMessage("Should be unique");
|
||||
SharedValidator.RuleFor(c => c.Implementation).NotEmpty();
|
||||
SharedValidator.RuleFor(c => c.ConfigContract).NotEmpty();
|
||||
|
||||
PostValidator.RuleFor(c => c.Fields).NotNull();
|
||||
}
|
||||
|
||||
private TProviderResource GetProviderById(int id)
|
||||
{
|
||||
var definition = _providerFactory.Get(id);
|
||||
_providerFactory.SetProviderCharacteristics(definition);
|
||||
|
||||
var resource = new TProviderResource();
|
||||
MapToResource(resource, definition);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
private List<TProviderResource> GetAll()
|
||||
{
|
||||
var providerDefinitions = _providerFactory.All().OrderBy(p => p.ImplementationName);
|
||||
|
||||
var result = new List<TProviderResource>(providerDefinitions.Count());
|
||||
|
||||
foreach (var definition in providerDefinitions)
|
||||
{
|
||||
_providerFactory.SetProviderCharacteristics(definition);
|
||||
|
||||
var providerResource = new TProviderResource();
|
||||
MapToResource(providerResource, definition);
|
||||
|
||||
result.Add(providerResource);
|
||||
}
|
||||
|
||||
return result.OrderBy(p => p.Name).ToList();
|
||||
}
|
||||
|
||||
private int CreateProvider(TProviderResource providerResource)
|
||||
{
|
||||
var providerDefinition = GetDefinition(providerResource, false);
|
||||
|
||||
if (providerDefinition.Enable)
|
||||
{
|
||||
Test(providerDefinition, false);
|
||||
}
|
||||
|
||||
providerDefinition = _providerFactory.Create(providerDefinition);
|
||||
|
||||
return providerDefinition.Id;
|
||||
}
|
||||
|
||||
private void UpdateProvider(TProviderResource providerResource)
|
||||
{
|
||||
var providerDefinition = GetDefinition(providerResource, false);
|
||||
|
||||
_providerFactory.Update(providerDefinition);
|
||||
}
|
||||
|
||||
private TProviderDefinition GetDefinition(TProviderResource providerResource, bool includeWarnings = false, bool validate = true)
|
||||
{
|
||||
var definition = new TProviderDefinition();
|
||||
|
||||
MapToModel(definition, providerResource);
|
||||
|
||||
if (validate)
|
||||
{
|
||||
Validate(definition, includeWarnings);
|
||||
}
|
||||
|
||||
return definition;
|
||||
}
|
||||
|
||||
protected virtual void MapToResource(TProviderResource resource, TProviderDefinition definition)
|
||||
{
|
||||
resource.Id = definition.Id;
|
||||
|
||||
resource.Name = definition.Name;
|
||||
resource.ImplementationName = definition.ImplementationName;
|
||||
resource.Implementation = definition.Implementation;
|
||||
resource.ConfigContract = definition.ConfigContract;
|
||||
resource.Message = definition.Message;
|
||||
|
||||
resource.Fields = SchemaBuilder.ToSchema(definition.Settings);
|
||||
|
||||
resource.InfoLink = string.Format("https://github.com/Lidarr/Lidarr/wiki/Supported-{0}#{1}",
|
||||
typeof(TProviderResource).Name.Replace("Resource", "s"),
|
||||
definition.Implementation.ToLower());
|
||||
}
|
||||
|
||||
protected virtual void MapToModel(TProviderDefinition definition, TProviderResource resource)
|
||||
{
|
||||
definition.Id = resource.Id;
|
||||
|
||||
definition.Name = resource.Name;
|
||||
definition.ImplementationName = resource.ImplementationName;
|
||||
definition.Implementation = resource.Implementation;
|
||||
definition.ConfigContract = resource.ConfigContract;
|
||||
definition.Message = resource.Message;
|
||||
|
||||
var configContract = ReflectionExtensions.CoreAssembly.FindTypeByName(definition.ConfigContract);
|
||||
definition.Settings = (IProviderConfig)SchemaBuilder.ReadFromSchema(resource.Fields, configContract);
|
||||
}
|
||||
|
||||
private void DeleteProvider(int id)
|
||||
{
|
||||
_providerFactory.Delete(id);
|
||||
}
|
||||
|
||||
private Response GetTemplates()
|
||||
{
|
||||
var defaultDefinitions = _providerFactory.GetDefaultDefinitions().OrderBy(p => p.ImplementationName).ToList();
|
||||
|
||||
var result = new List<TProviderResource>(defaultDefinitions.Count());
|
||||
|
||||
foreach (var providerDefinition in defaultDefinitions)
|
||||
{
|
||||
var providerResource = new TProviderResource();
|
||||
MapToResource(providerResource, providerDefinition);
|
||||
|
||||
var presetDefinitions = _providerFactory.GetPresetDefinitions(providerDefinition);
|
||||
|
||||
providerResource.Presets = presetDefinitions.Select(v =>
|
||||
{
|
||||
var presetResource = new TProviderResource();
|
||||
MapToResource(presetResource, v);
|
||||
|
||||
return presetResource as ProviderResource;
|
||||
}).ToList();
|
||||
|
||||
result.Add(providerResource);
|
||||
}
|
||||
|
||||
return result.AsResponse();
|
||||
}
|
||||
|
||||
private Response Test(TProviderResource providerResource)
|
||||
{
|
||||
// Don't validate when getting the definition so we can validate afterwards (avoids validation being skipped because the provider is disabled)
|
||||
var providerDefinition = GetDefinition(providerResource, true, false);
|
||||
|
||||
Validate(providerDefinition, true);
|
||||
Test(providerDefinition, true);
|
||||
|
||||
return "{}";
|
||||
}
|
||||
|
||||
|
||||
private Response RequestAction(string action, TProviderResource providerResource)
|
||||
{
|
||||
var providerDefinition = GetDefinition(providerResource, true, false);
|
||||
|
||||
var query = ((IDictionary<string, object>)Request.Query.ToDictionary()).ToDictionary(k => k.Key, k => k.Value.ToString());
|
||||
|
||||
var data = _providerFactory.RequestAction(providerDefinition, action, query);
|
||||
Response resp = JsonConvert.SerializeObject(data);
|
||||
resp.ContentType = "application/json";
|
||||
return resp;
|
||||
}
|
||||
|
||||
protected virtual void Validate(TProviderDefinition definition, bool includeWarnings)
|
||||
{
|
||||
var validationResult = definition.Settings.Validate();
|
||||
|
||||
VerifyValidationResult(validationResult, includeWarnings);
|
||||
}
|
||||
|
||||
protected virtual void Test(TProviderDefinition definition, bool includeWarnings)
|
||||
{
|
||||
var validationResult = _providerFactory.Test(definition);
|
||||
|
||||
VerifyValidationResult(validationResult, includeWarnings);
|
||||
}
|
||||
|
||||
protected void VerifyValidationResult(ValidationResult validationResult, bool includeWarnings)
|
||||
{
|
||||
var result = new NzbDroneValidationResult(validationResult.Errors);
|
||||
|
||||
if (includeWarnings && (!result.IsValid || result.HasWarnings))
|
||||
{
|
||||
throw new ValidationException(result.Failures);
|
||||
}
|
||||
|
||||
if (!result.IsValid)
|
||||
{
|
||||
throw new ValidationException(result.Errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Lidarr.Http.ClientSchema;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
|
||||
namespace NzbDrone.Api
|
||||
{
|
||||
public class ProviderResource : RestResource
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public List<Field> Fields { get; set; }
|
||||
public string ImplementationName { get; set; }
|
||||
public string Implementation { get; set; }
|
||||
public string ConfigContract { get; set; }
|
||||
public string InfoLink { get; set; }
|
||||
public ProviderMessage Message { get; set; }
|
||||
|
||||
public List<ProviderResource> Presets { get; set; }
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using Lidarr.Http;
|
||||
using Lidarr.Http.Mapping;
|
||||
|
||||
namespace NzbDrone.Api.Qualities
|
||||
{
|
||||
public class QualityDefinitionModule : LidarrRestModule<QualityDefinitionResource>
|
||||
{
|
||||
private readonly IQualityDefinitionService _qualityDefinitionService;
|
||||
|
||||
public QualityDefinitionModule(IQualityDefinitionService qualityDefinitionService)
|
||||
{
|
||||
_qualityDefinitionService = qualityDefinitionService;
|
||||
|
||||
GetResourceAll = GetAll;
|
||||
|
||||
GetResourceById = GetById;
|
||||
|
||||
UpdateResource = Update;
|
||||
}
|
||||
|
||||
private void Update(QualityDefinitionResource resource)
|
||||
{
|
||||
var model = resource.ToModel();
|
||||
_qualityDefinitionService.Update(model);
|
||||
}
|
||||
|
||||
private QualityDefinitionResource GetById(int id)
|
||||
{
|
||||
return _qualityDefinitionService.GetById(id).ToResource();
|
||||
}
|
||||
|
||||
private List<QualityDefinitionResource> GetAll()
|
||||
{
|
||||
return _qualityDefinitionService.All().ToResource();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Api.Qualities
|
||||
{
|
||||
public class QualityDefinitionResource : RestResource
|
||||
{
|
||||
public Quality Quality { get; set; }
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
public int Weight { get; set; }
|
||||
|
||||
public double? MinSize { get; set; }
|
||||
public double? MaxSize { get; set; }
|
||||
}
|
||||
|
||||
public static class QualityDefinitionResourceMapper
|
||||
{
|
||||
public static QualityDefinitionResource ToResource(this QualityDefinition model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new QualityDefinitionResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
Quality = model.Quality,
|
||||
|
||||
Title = model.Title,
|
||||
|
||||
Weight = model.Weight,
|
||||
|
||||
MinSize = model.MinSize,
|
||||
MaxSize = model.MaxSize
|
||||
};
|
||||
}
|
||||
|
||||
public static QualityDefinition ToModel(this QualityDefinitionResource resource)
|
||||
{
|
||||
if (resource == null) return null;
|
||||
|
||||
return new QualityDefinition
|
||||
{
|
||||
Id = resource.Id,
|
||||
|
||||
Quality = resource.Quality,
|
||||
|
||||
Title = resource.Title,
|
||||
|
||||
Weight = resource.Weight,
|
||||
|
||||
MinSize = resource.MinSize,
|
||||
MaxSize = resource.MaxSize
|
||||
};
|
||||
}
|
||||
|
||||
public static List<QualityDefinitionResource> ToResource(this IEnumerable<QualityDefinition> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
using System;
|
||||
using Nancy;
|
||||
using Nancy.Responses;
|
||||
using Lidarr.Http.Extensions;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Pending;
|
||||
using NzbDrone.Core.Download.TrackedDownloads;
|
||||
using NzbDrone.Core.Queue;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Queue
|
||||
{
|
||||
public class QueueActionModule : LidarrRestModule<QueueResource>
|
||||
{
|
||||
private readonly IQueueService _queueService;
|
||||
private readonly ITrackedDownloadService _trackedDownloadService;
|
||||
private readonly ICompletedDownloadService _completedDownloadService;
|
||||
private readonly IFailedDownloadService _failedDownloadService;
|
||||
private readonly IProvideDownloadClient _downloadClientProvider;
|
||||
private readonly IPendingReleaseService _pendingReleaseService;
|
||||
private readonly IDownloadService _downloadService;
|
||||
|
||||
public QueueActionModule(IQueueService queueService,
|
||||
ITrackedDownloadService trackedDownloadService,
|
||||
ICompletedDownloadService completedDownloadService,
|
||||
IFailedDownloadService failedDownloadService,
|
||||
IProvideDownloadClient downloadClientProvider,
|
||||
IPendingReleaseService pendingReleaseService,
|
||||
IDownloadService downloadService)
|
||||
{
|
||||
_queueService = queueService;
|
||||
_trackedDownloadService = trackedDownloadService;
|
||||
_completedDownloadService = completedDownloadService;
|
||||
_failedDownloadService = failedDownloadService;
|
||||
_downloadClientProvider = downloadClientProvider;
|
||||
_pendingReleaseService = pendingReleaseService;
|
||||
_downloadService = downloadService;
|
||||
|
||||
Delete[@"/(?<id>[\d]{1,10})"] = x => Remove((int)x.Id);
|
||||
Post["/import"] = x => Import();
|
||||
Post["/grab"] = x => Grab();
|
||||
}
|
||||
|
||||
private Response Remove(int id)
|
||||
{
|
||||
var blacklist = false;
|
||||
var blacklistQuery = Request.Query.blacklist;
|
||||
|
||||
if (blacklistQuery.HasValue)
|
||||
{
|
||||
blacklist = Convert.ToBoolean(blacklistQuery.Value);
|
||||
}
|
||||
|
||||
var pendingRelease = _pendingReleaseService.FindPendingQueueItem(id);
|
||||
|
||||
if (pendingRelease != null)
|
||||
{
|
||||
_pendingReleaseService.RemovePendingQueueItems(pendingRelease.Id);
|
||||
|
||||
return new object().AsResponse();
|
||||
}
|
||||
|
||||
var trackedDownload = GetTrackedDownload(id);
|
||||
|
||||
if (trackedDownload == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var downloadClient = _downloadClientProvider.Get(trackedDownload.DownloadClient);
|
||||
|
||||
if (downloadClient == null)
|
||||
{
|
||||
throw new BadRequestException();
|
||||
}
|
||||
|
||||
downloadClient.RemoveItem(trackedDownload.DownloadItem.DownloadId, true);
|
||||
|
||||
if (blacklist)
|
||||
{
|
||||
_failedDownloadService.MarkAsFailed(trackedDownload.DownloadItem.DownloadId);
|
||||
}
|
||||
|
||||
return new object().AsResponse();
|
||||
}
|
||||
|
||||
private JsonResponse<QueueResource> Import()
|
||||
{
|
||||
var resource = Request.Body.FromJson<QueueResource>();
|
||||
var trackedDownload = GetTrackedDownload(resource.Id);
|
||||
|
||||
_completedDownloadService.Process(trackedDownload, true);
|
||||
|
||||
return resource.AsResponse();
|
||||
}
|
||||
|
||||
private JsonResponse<QueueResource> Grab()
|
||||
{
|
||||
var resource = Request.Body.FromJson<QueueResource>();
|
||||
|
||||
var pendingRelease = _pendingReleaseService.FindPendingQueueItem(resource.Id);
|
||||
|
||||
if (pendingRelease == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
_downloadService.DownloadReport(pendingRelease.RemoteAlbum);
|
||||
|
||||
return resource.AsResponse();
|
||||
}
|
||||
|
||||
private TrackedDownload GetTrackedDownload(int queueId)
|
||||
{
|
||||
var queueItem = _queueService.Find(queueId);
|
||||
|
||||
if (queueItem == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var trackedDownload = _trackedDownloadService.Find(queueItem.DownloadId);
|
||||
|
||||
if (trackedDownload == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
return trackedDownload;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
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 Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Queue
|
||||
{
|
||||
public class QueueModule : LidarrRestModuleWithSignalR<QueueResource, Core.Queue.Queue>,
|
||||
IHandle<QueueUpdatedEvent>, IHandle<PendingReleasesUpdatedEvent>
|
||||
{
|
||||
private readonly IQueueService _queueService;
|
||||
private readonly IPendingReleaseService _pendingReleaseService;
|
||||
|
||||
public QueueModule(IBroadcastSignalRMessage broadcastSignalRMessage, IQueueService queueService, IPendingReleaseService pendingReleaseService)
|
||||
: base(broadcastSignalRMessage)
|
||||
{
|
||||
_queueService = queueService;
|
||||
_pendingReleaseService = pendingReleaseService;
|
||||
GetResourceAll = GetQueue;
|
||||
}
|
||||
|
||||
private List<QueueResource> GetQueue()
|
||||
{
|
||||
return GetQueueItems().ToResource();
|
||||
}
|
||||
|
||||
private IEnumerable<Core.Queue.Queue> GetQueueItems()
|
||||
{
|
||||
var queue = _queueService.GetQueue();
|
||||
var pending = _pendingReleaseService.GetPendingQueue();
|
||||
|
||||
return queue.Concat(pending);
|
||||
}
|
||||
|
||||
public void Handle(QueueUpdatedEvent message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Sync);
|
||||
}
|
||||
|
||||
public void Handle(PendingReleasesUpdatedEvent message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Sync);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Api.Series;
|
||||
using NzbDrone.Api.Episodes;
|
||||
using NzbDrone.Api.Music;
|
||||
using NzbDrone.Api.Albums;
|
||||
using NzbDrone.Core.Download.TrackedDownloads;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using System.Linq;
|
||||
|
||||
namespace NzbDrone.Api.Queue
|
||||
{
|
||||
public class QueueResource : RestResource
|
||||
{
|
||||
public ArtistResource Artist { get; set; }
|
||||
public AlbumResource Album { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public decimal Size { get; set; }
|
||||
public string Title { get; set; }
|
||||
public decimal Sizeleft { get; set; }
|
||||
public TimeSpan? Timeleft { get; set; }
|
||||
public DateTime? EstimatedCompletionTime { get; set; }
|
||||
public string Status { get; set; }
|
||||
public string TrackedDownloadStatus { get; set; }
|
||||
public List<TrackedDownloadStatusMessage> StatusMessages { get; set; }
|
||||
public string DownloadId { get; set; }
|
||||
public DownloadProtocol Protocol { get; set; }
|
||||
}
|
||||
|
||||
public static class QueueResourceMapper
|
||||
{
|
||||
public static QueueResource ToResource(this Core.Queue.Queue model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new QueueResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
Artist = model.Artist.ToResource(),
|
||||
Album = model.Album.ToResource(),
|
||||
Quality = model.Quality,
|
||||
Size = model.Size,
|
||||
Title = model.Title,
|
||||
Sizeleft = model.Sizeleft,
|
||||
Timeleft = model.Timeleft,
|
||||
EstimatedCompletionTime = model.EstimatedCompletionTime,
|
||||
Status = model.Status,
|
||||
TrackedDownloadStatus = model.TrackedDownloadStatus,
|
||||
StatusMessages = model.StatusMessages,
|
||||
DownloadId = model.DownloadId,
|
||||
Protocol = model.Protocol
|
||||
};
|
||||
}
|
||||
|
||||
public static List<QueueResource> ToResource(this IEnumerable<Core.Queue.Queue> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.RemotePathMappings;
|
||||
using NzbDrone.Core.Validation.Paths;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.RemotePathMappings
|
||||
{
|
||||
public class RemotePathMappingModule : LidarrRestModule<RemotePathMappingResource>
|
||||
{
|
||||
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<RemotePathMappingResource> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.RemotePathMappings;
|
||||
|
||||
namespace NzbDrone.Api.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<RemotePathMappingResource> ToResource(this IEnumerable<RemotePathMapping> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using FluentValidation.Results;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Restrictions;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.Restrictions
|
||||
{
|
||||
public class RestrictionModule : LidarrRestModule<RestrictionResource>
|
||||
{
|
||||
private readonly IRestrictionService _restrictionService;
|
||||
|
||||
|
||||
public RestrictionModule(IRestrictionService restrictionService)
|
||||
{
|
||||
_restrictionService = restrictionService;
|
||||
|
||||
GetResourceById = GetRestriction;
|
||||
GetResourceAll = GetAllRestrictions;
|
||||
CreateResource = CreateRestriction;
|
||||
UpdateResource = UpdateRestriction;
|
||||
DeleteResource = DeleteRestriction;
|
||||
|
||||
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 GetRestriction(int id)
|
||||
{
|
||||
return _restrictionService.Get(id).ToResource();
|
||||
}
|
||||
|
||||
private List<RestrictionResource> GetAllRestrictions()
|
||||
{
|
||||
return _restrictionService.All().ToResource();
|
||||
}
|
||||
|
||||
private int CreateRestriction(RestrictionResource resource)
|
||||
{
|
||||
return _restrictionService.Add(resource.ToModel()).Id;
|
||||
}
|
||||
|
||||
private void UpdateRestriction(RestrictionResource resource)
|
||||
{
|
||||
_restrictionService.Update(resource.ToModel());
|
||||
}
|
||||
|
||||
private void DeleteRestriction(int id)
|
||||
{
|
||||
_restrictionService.Delete(id);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.Restrictions;
|
||||
|
||||
namespace NzbDrone.Api.Restrictions
|
||||
{
|
||||
public class RestrictionResource : RestResource
|
||||
{
|
||||
public string Required { get; set; }
|
||||
public string Preferred { get; set; }
|
||||
public string Ignored { get; set; }
|
||||
public HashSet<int> Tags { get; set; }
|
||||
|
||||
public RestrictionResource()
|
||||
{
|
||||
Tags = new HashSet<int>();
|
||||
}
|
||||
}
|
||||
|
||||
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<int>(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<int>(resource.Tags)
|
||||
};
|
||||
}
|
||||
|
||||
public static List<RestrictionResource> ToResource(this IEnumerable<Restriction> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
using NzbDrone.Core.Validation.Paths;
|
||||
using NzbDrone.SignalR;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.RootFolders
|
||||
{
|
||||
public class RootFolderModule : LidarrRestModuleWithSignalR<RootFolderResource, RootFolder>
|
||||
{
|
||||
private readonly IRootFolderService _rootFolderService;
|
||||
|
||||
public RootFolderModule(IRootFolderService rootFolderService,
|
||||
IBroadcastSignalRMessage signalRBroadcaster,
|
||||
RootFolderValidator rootFolderValidator,
|
||||
PathExistsValidator pathExistsValidator,
|
||||
MappedNetworkDriveValidator mappedNetworkDriveValidator,
|
||||
StartupFolderValidator startupFolderValidator,
|
||||
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(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<RootFolderResource> GetRootFolders()
|
||||
{
|
||||
return _rootFolderService.AllWithUnmappedFolders().ToResource();
|
||||
}
|
||||
|
||||
private void DeleteFolder(int id)
|
||||
{
|
||||
_rootFolderService.Remove(id);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
|
||||
namespace NzbDrone.Api.RootFolders
|
||||
{
|
||||
public class RootFolderResource : RestResource
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public long? FreeSpace { get; set; }
|
||||
|
||||
public List<UnmappedFolder> 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<RootFolderResource> ToResource(this IEnumerable<RootFolder> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
using Nancy;
|
||||
using Lidarr.Http.Extensions;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Api.SeasonPass
|
||||
{
|
||||
public class SeasonPassModule : NzbDroneApiModule
|
||||
{
|
||||
private readonly IEpisodeMonitoredService _episodeMonitoredService;
|
||||
|
||||
public SeasonPassModule(IEpisodeMonitoredService episodeMonitoredService)
|
||||
: base("/seasonpass")
|
||||
{
|
||||
_episodeMonitoredService = episodeMonitoredService;
|
||||
Post["/"] = series => UpdateAll();
|
||||
}
|
||||
|
||||
private Response UpdateAll()
|
||||
{
|
||||
//Read from request
|
||||
var request = Request.Body.FromJson<SeasonPassResource>();
|
||||
|
||||
foreach (var s in request.Series)
|
||||
{
|
||||
_episodeMonitoredService.SetEpisodeMonitoredStatus(s, request.MonitoringOptions);
|
||||
}
|
||||
|
||||
return "ok".AsResponse(HttpStatusCode.Accepted);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue