mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-13 16:43:58 -07:00
New: Use ASP.NET Core instead of Nancy
This commit is contained in:
parent
fe956f340c
commit
c247d07e84
161 changed files with 2893 additions and 3665 deletions
|
@ -78,7 +78,9 @@ export default {
|
||||||
const promise = createAjaxRequest({
|
const promise = createAjaxRequest({
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
url: '/qualityDefinition/update',
|
url: '/qualityDefinition/update',
|
||||||
data: JSON.stringify(upatedDefinitions)
|
data: JSON.stringify(upatedDefinitions),
|
||||||
|
contentType: 'application/json',
|
||||||
|
dataType: 'json'
|
||||||
}).request;
|
}).request;
|
||||||
|
|
||||||
promise.done((data) => {
|
promise.done((data) => {
|
||||||
|
|
|
@ -88,6 +88,7 @@ export const actionHandlers = handleThunks({
|
||||||
const promise = createAjaxRequest({
|
const promise = createAjaxRequest({
|
||||||
url: '/history/failed',
|
url: '/history/failed',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
data: {
|
data: {
|
||||||
id: historyId
|
id: historyId
|
||||||
}
|
}
|
||||||
|
@ -109,4 +110,3 @@ export const reducers = createHandleActions({
|
||||||
}
|
}
|
||||||
|
|
||||||
}, defaultState, section);
|
}, defaultState, section);
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,7 @@ export const actionHandlers = handleThunks({
|
||||||
const promise = createAjaxRequest({
|
const promise = createAjaxRequest({
|
||||||
url: '/history/failed',
|
url: '/history/failed',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
data: {
|
data: {
|
||||||
id: historyId
|
id: historyId
|
||||||
}
|
}
|
||||||
|
@ -101,4 +102,3 @@ export const reducers = createHandleActions({
|
||||||
}
|
}
|
||||||
|
|
||||||
}, defaultState, section);
|
}, defaultState, section);
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,7 @@ export const actionHandlers = handleThunks({
|
||||||
url: '/blacklist/bulk',
|
url: '/blacklist/bulk',
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
|
contentType: 'application/json',
|
||||||
data: JSON.stringify({ ids })
|
data: JSON.stringify({ ids })
|
||||||
}).request;
|
}).request;
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,8 @@ export function executeCommandHelper( payload, dispatch) {
|
||||||
const promise = createAjaxRequest({
|
const promise = createAjaxRequest({
|
||||||
url: '/command',
|
url: '/command',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: JSON.stringify(payload)
|
data: JSON.stringify(payload),
|
||||||
|
dataType: 'json'
|
||||||
}).request;
|
}).request;
|
||||||
|
|
||||||
return promise.then((data) => {
|
return promise.then((data) => {
|
||||||
|
|
|
@ -264,6 +264,7 @@ export const actionHandlers = handleThunks({
|
||||||
const promise = createAjaxRequest({
|
const promise = createAjaxRequest({
|
||||||
url: '/history/failed',
|
url: '/history/failed',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
data: {
|
data: {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
|
@ -396,6 +396,7 @@ export const actionHandlers = handleThunks({
|
||||||
url: `/queue/bulk?removeFromClient=${remove}&blacklist=${blacklist}&skipredownload=${skipredownload}`,
|
url: `/queue/bulk?removeFromClient=${remove}&blacklist=${blacklist}&skipredownload=${skipredownload}`,
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
|
contentType: 'application/json',
|
||||||
data: JSON.stringify({ ids })
|
data: JSON.stringify({ ids })
|
||||||
}).request;
|
}).request;
|
||||||
|
|
||||||
|
@ -453,4 +454,3 @@ export const reducers = createHandleActions({
|
||||||
})
|
})
|
||||||
|
|
||||||
}, defaultState, section);
|
}, defaultState, section);
|
||||||
|
|
||||||
|
|
|
@ -271,6 +271,7 @@ export const actionHandlers = handleThunks({
|
||||||
const promise = createAjaxRequest({
|
const promise = createAjaxRequest({
|
||||||
url: '/release',
|
url: '/release',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
contentType: 'application/json',
|
contentType: 'application/json',
|
||||||
data: JSON.stringify(payload)
|
data: JSON.stringify(payload)
|
||||||
}).request;
|
}).request;
|
||||||
|
|
|
@ -115,6 +115,7 @@ export const actionHandlers = handleThunks({
|
||||||
const promise = createAjaxRequest({
|
const promise = createAjaxRequest({
|
||||||
url: '/artist',
|
url: '/artist',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
contentType: 'application/json',
|
contentType: 'application/json',
|
||||||
data: JSON.stringify(newArtist)
|
data: JSON.stringify(newArtist)
|
||||||
}).request;
|
}).request;
|
||||||
|
|
|
@ -53,7 +53,8 @@ export const actionHandlers = handleThunks({
|
||||||
const promise = createAjaxRequest({
|
const promise = createAjaxRequest({
|
||||||
url: '/tag',
|
url: '/tag',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: JSON.stringify(payload.tag)
|
data: JSON.stringify(payload.tag),
|
||||||
|
dataType: 'json'
|
||||||
}).request;
|
}).request;
|
||||||
|
|
||||||
promise.done((data) => {
|
promise.done((data) => {
|
||||||
|
|
|
@ -7,18 +7,6 @@ function isRelative(ajaxOptions) {
|
||||||
return !absUrlRegex.test(ajaxOptions.url);
|
return !absUrlRegex.test(ajaxOptions.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveBodyToQuery(ajaxOptions) {
|
|
||||||
if (ajaxOptions.data && ajaxOptions.type === 'DELETE') {
|
|
||||||
if (ajaxOptions.url.contains('?')) {
|
|
||||||
ajaxOptions.url += '&';
|
|
||||||
} else {
|
|
||||||
ajaxOptions.url += '?';
|
|
||||||
}
|
|
||||||
ajaxOptions.url += $.param(ajaxOptions.data);
|
|
||||||
delete ajaxOptions.data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addRootUrl(ajaxOptions) {
|
function addRootUrl(ajaxOptions) {
|
||||||
ajaxOptions.url = apiRoot + ajaxOptions.url;
|
ajaxOptions.url = apiRoot + ajaxOptions.url;
|
||||||
}
|
}
|
||||||
|
@ -32,7 +20,7 @@ function addContentType(ajaxOptions) {
|
||||||
if (
|
if (
|
||||||
ajaxOptions.contentType == null &&
|
ajaxOptions.contentType == null &&
|
||||||
ajaxOptions.dataType === 'json' &&
|
ajaxOptions.dataType === 'json' &&
|
||||||
(ajaxOptions.method === 'PUT' || ajaxOptions.method === 'POST')) {
|
(ajaxOptions.method === 'PUT' || ajaxOptions.method === 'POST' || ajaxOptions.method === 'DELETE')) {
|
||||||
ajaxOptions.contentType = 'application/json';
|
ajaxOptions.contentType = 'application/json';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +40,6 @@ export default function createAjaxRequest(originalAjaxOptions) {
|
||||||
const ajaxOptions = { ...originalAjaxOptions };
|
const ajaxOptions = { ...originalAjaxOptions };
|
||||||
|
|
||||||
if (isRelative(ajaxOptions)) {
|
if (isRelative(ajaxOptions)) {
|
||||||
moveBodyToQuery(ajaxOptions);
|
|
||||||
addRootUrl(ajaxOptions);
|
addRootUrl(ajaxOptions);
|
||||||
addApiKey(ajaxOptions);
|
addApiKey(ajaxOptions);
|
||||||
addContentType(ajaxOptions);
|
addContentType(ajaxOptions);
|
||||||
|
|
|
@ -1,27 +1,25 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http.Extensions;
|
using Lidarr.Http;
|
||||||
using Nancy;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.AlbumStudio
|
namespace Lidarr.Api.V1.AlbumStudio
|
||||||
{
|
{
|
||||||
public class AlbumStudioModule : LidarrV1Module
|
[V1ApiController]
|
||||||
|
public class AlbumStudioController : Controller
|
||||||
{
|
{
|
||||||
private readonly IArtistService _artistService;
|
private readonly IArtistService _artistService;
|
||||||
private readonly IAlbumMonitoredService _albumMonitoredService;
|
private readonly IAlbumMonitoredService _albumMonitoredService;
|
||||||
|
|
||||||
public AlbumStudioModule(IArtistService artistService, IAlbumMonitoredService albumMonitoredService)
|
public AlbumStudioController(IArtistService artistService, IAlbumMonitoredService albumMonitoredService)
|
||||||
: base("/albumstudio")
|
|
||||||
{
|
{
|
||||||
_artistService = artistService;
|
_artistService = artistService;
|
||||||
_albumMonitoredService = albumMonitoredService;
|
_albumMonitoredService = albumMonitoredService;
|
||||||
Post("/", artist => UpdateAll());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private object UpdateAll()
|
[HttpPost]
|
||||||
|
public IActionResult UpdateAll([FromBody] AlbumStudioResource request)
|
||||||
{
|
{
|
||||||
//Read from request
|
|
||||||
var request = Request.Body.FromJson<AlbumStudioResource>();
|
|
||||||
var artistToUpdate = _artistService.GetArtists(request.Artist.Select(s => s.Id));
|
var artistToUpdate = _artistService.GetArtists(request.Artist.Select(s => s.Id));
|
||||||
|
|
||||||
foreach (var s in request.Artist)
|
foreach (var s in request.Artist)
|
||||||
|
@ -41,7 +39,7 @@ namespace Lidarr.Api.V1.AlbumStudio
|
||||||
_albumMonitoredService.SetAlbumMonitoredStatus(artist, request.MonitoringOptions);
|
_albumMonitoredService.SetAlbumMonitoredStatus(artist, request.MonitoringOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResponseWithCode("ok", HttpStatusCode.Accepted);
|
return Accepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.Extensions;
|
using Lidarr.Http.Extensions;
|
||||||
using Nancy;
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.ArtistStats;
|
using NzbDrone.Core.ArtistStats;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
using NzbDrone.Core.Datastore.Events;
|
||||||
|
@ -21,7 +22,8 @@ using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Albums
|
namespace Lidarr.Api.V1.Albums
|
||||||
{
|
{
|
||||||
public class AlbumModule : AlbumModuleWithSignalR,
|
[V1ApiController]
|
||||||
|
public class AlbumController : AlbumControllerWithSignalR,
|
||||||
IHandle<AlbumGrabbedEvent>,
|
IHandle<AlbumGrabbedEvent>,
|
||||||
IHandle<AlbumEditedEvent>,
|
IHandle<AlbumEditedEvent>,
|
||||||
IHandle<AlbumUpdatedEvent>,
|
IHandle<AlbumUpdatedEvent>,
|
||||||
|
@ -33,7 +35,7 @@ namespace Lidarr.Api.V1.Albums
|
||||||
protected readonly IReleaseService _releaseService;
|
protected readonly IReleaseService _releaseService;
|
||||||
protected readonly IAddAlbumService _addAlbumService;
|
protected readonly IAddAlbumService _addAlbumService;
|
||||||
|
|
||||||
public AlbumModule(IArtistService artistService,
|
public AlbumController(IArtistService artistService,
|
||||||
IAlbumService albumService,
|
IAlbumService albumService,
|
||||||
IAddAlbumService addAlbumService,
|
IAddAlbumService addAlbumService,
|
||||||
IReleaseService releaseService,
|
IReleaseService releaseService,
|
||||||
|
@ -50,12 +52,6 @@ namespace Lidarr.Api.V1.Albums
|
||||||
_releaseService = releaseService;
|
_releaseService = releaseService;
|
||||||
_addAlbumService = addAlbumService;
|
_addAlbumService = addAlbumService;
|
||||||
|
|
||||||
GetResourceAll = GetAlbums;
|
|
||||||
CreateResource = AddAlbum;
|
|
||||||
UpdateResource = UpdateAlbum;
|
|
||||||
DeleteResource = DeleteAlbum;
|
|
||||||
Put("/monitor", x => SetAlbumsMonitored());
|
|
||||||
|
|
||||||
PostValidator.RuleFor(s => s.ForeignAlbumId).NotEmpty();
|
PostValidator.RuleFor(s => s.ForeignAlbumId).NotEmpty();
|
||||||
PostValidator.RuleFor(s => s.Artist.QualityProfileId).SetValidator(qualityProfileExistsValidator);
|
PostValidator.RuleFor(s => s.Artist.QualityProfileId).SetValidator(qualityProfileExistsValidator);
|
||||||
PostValidator.RuleFor(s => s.Artist.MetadataProfileId).SetValidator(metadataProfileExistsValidator);
|
PostValidator.RuleFor(s => s.Artist.MetadataProfileId).SetValidator(metadataProfileExistsValidator);
|
||||||
|
@ -63,14 +59,13 @@ namespace Lidarr.Api.V1.Albums
|
||||||
PostValidator.RuleFor(s => s.Artist.ForeignArtistId).NotEmpty();
|
PostValidator.RuleFor(s => s.Artist.ForeignArtistId).NotEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<AlbumResource> GetAlbums()
|
[HttpGet]
|
||||||
|
public List<AlbumResource> GetAlbums([FromQuery]int? artistId,
|
||||||
|
[FromQuery] List<int> albumIds,
|
||||||
|
[FromQuery]string foreignAlbumId,
|
||||||
|
[FromQuery]bool includeAllArtistAlbums = false)
|
||||||
{
|
{
|
||||||
var artistIdQuery = Request.Query.ArtistId;
|
if (!artistId.HasValue && !albumIds.Any() && foreignAlbumId.IsNullOrWhiteSpace())
|
||||||
var albumIdsQuery = Request.Query.AlbumIds;
|
|
||||||
var foreignIdQuery = Request.Query.ForeignAlbumId;
|
|
||||||
var includeAllArtistAlbumsQuery = Request.Query.IncludeAllArtistAlbums;
|
|
||||||
|
|
||||||
if (!Request.Query.ArtistId.HasValue && !albumIdsQuery.HasValue && !foreignIdQuery.HasValue)
|
|
||||||
{
|
{
|
||||||
var albums = _albumService.GetAllAlbums();
|
var albums = _albumService.GetAllAlbums();
|
||||||
|
|
||||||
|
@ -93,17 +88,13 @@ namespace Lidarr.Api.V1.Albums
|
||||||
return MapToResource(albums, false);
|
return MapToResource(albums, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (artistIdQuery.HasValue)
|
if (artistId.HasValue)
|
||||||
{
|
{
|
||||||
int artistId = Convert.ToInt32(artistIdQuery.Value);
|
return MapToResource(_albumService.GetAlbumsByArtist(artistId.Value), false);
|
||||||
|
|
||||||
return MapToResource(_albumService.GetAlbumsByArtist(artistId), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foreignIdQuery.HasValue)
|
if (foreignAlbumId.IsNotNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
string foreignAlbumId = foreignIdQuery.Value.ToString();
|
|
||||||
|
|
||||||
var album = _albumService.FindById(foreignAlbumId);
|
var album = _albumService.FindById(foreignAlbumId);
|
||||||
|
|
||||||
if (album == null)
|
if (album == null)
|
||||||
|
@ -111,7 +102,7 @@ namespace Lidarr.Api.V1.Albums
|
||||||
return MapToResource(new List<Album>(), false);
|
return MapToResource(new List<Album>(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeAllArtistAlbumsQuery.HasValue && Convert.ToBoolean(includeAllArtistAlbumsQuery.Value))
|
if (includeAllArtistAlbums)
|
||||||
{
|
{
|
||||||
return MapToResource(_albumService.GetAlbumsByArtist(album.ArtistId), false);
|
return MapToResource(_albumService.GetAlbumsByArtist(album.ArtistId), false);
|
||||||
}
|
}
|
||||||
|
@ -121,23 +112,19 @@ namespace Lidarr.Api.V1.Albums
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string albumIdsValue = albumIdsQuery.Value.ToString();
|
|
||||||
|
|
||||||
var albumIds = albumIdsValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Select(e => Convert.ToInt32(e))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
return MapToResource(_albumService.GetAlbums(albumIds), false);
|
return MapToResource(_albumService.GetAlbums(albumIds), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int AddAlbum(AlbumResource albumResource)
|
[RestPostById]
|
||||||
|
public ActionResult<AlbumResource> AddAlbum(AlbumResource albumResource)
|
||||||
{
|
{
|
||||||
var album = _addAlbumService.AddAlbum(albumResource.ToModel());
|
var album = _addAlbumService.AddAlbum(albumResource.ToModel());
|
||||||
|
|
||||||
return album.Id;
|
return Created(album.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateAlbum(AlbumResource albumResource)
|
[RestPutById]
|
||||||
|
public ActionResult<AlbumResource> UpdateAlbum(AlbumResource albumResource)
|
||||||
{
|
{
|
||||||
var album = _albumService.GetAlbum(albumResource.Id);
|
var album = _albumService.GetAlbum(albumResource.Id);
|
||||||
|
|
||||||
|
@ -147,9 +134,12 @@ namespace Lidarr.Api.V1.Albums
|
||||||
_releaseService.UpdateMany(model.AlbumReleases.Value);
|
_releaseService.UpdateMany(model.AlbumReleases.Value);
|
||||||
|
|
||||||
BroadcastResourceChange(ModelAction.Updated, model.Id);
|
BroadcastResourceChange(ModelAction.Updated, model.Id);
|
||||||
|
|
||||||
|
return Accepted(model.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteAlbum(int id)
|
[RestDeleteById]
|
||||||
|
public void DeleteAlbum(int id)
|
||||||
{
|
{
|
||||||
var deleteFiles = Request.GetBooleanQueryParameter("deleteFiles");
|
var deleteFiles = Request.GetBooleanQueryParameter("deleteFiles");
|
||||||
var addImportListExclusion = Request.GetBooleanQueryParameter("addImportListExclusion");
|
var addImportListExclusion = Request.GetBooleanQueryParameter("addImportListExclusion");
|
||||||
|
@ -157,15 +147,15 @@ namespace Lidarr.Api.V1.Albums
|
||||||
_albumService.DeleteAlbum(id, deleteFiles, addImportListExclusion);
|
_albumService.DeleteAlbum(id, deleteFiles, addImportListExclusion);
|
||||||
}
|
}
|
||||||
|
|
||||||
private object SetAlbumsMonitored()
|
[HttpPut("monitor")]
|
||||||
|
public IActionResult SetAlbumsMonitored([FromBody]AlbumsMonitoredResource resource)
|
||||||
{
|
{
|
||||||
var resource = Request.Body.FromJson<AlbumsMonitoredResource>();
|
|
||||||
|
|
||||||
_albumService.SetMonitored(resource.AlbumIds, resource.Monitored);
|
_albumService.SetMonitored(resource.AlbumIds, resource.Monitored);
|
||||||
|
|
||||||
return ResponseWithCode(MapToResource(_albumService.GetAlbums(resource.AlbumIds), false), HttpStatusCode.Accepted);
|
return Accepted(MapToResource(_albumService.GetAlbums(resource.AlbumIds), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(AlbumGrabbedEvent message)
|
public void Handle(AlbumGrabbedEvent message)
|
||||||
{
|
{
|
||||||
foreach (var album in message.Album.Albums)
|
foreach (var album in message.Album.Albums)
|
||||||
|
@ -177,31 +167,37 @@ namespace Lidarr.Api.V1.Albums
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(AlbumEditedEvent message)
|
public void Handle(AlbumEditedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Updated, MapToResource(message.Album, true));
|
BroadcastResourceChange(ModelAction.Updated, MapToResource(message.Album, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(AlbumUpdatedEvent message)
|
public void Handle(AlbumUpdatedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Updated, MapToResource(message.Album, true));
|
BroadcastResourceChange(ModelAction.Updated, MapToResource(message.Album, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(AlbumDeletedEvent message)
|
public void Handle(AlbumDeletedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Deleted, message.Album.ToResource());
|
BroadcastResourceChange(ModelAction.Deleted, message.Album.ToResource());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(AlbumImportedEvent message)
|
public void Handle(AlbumImportedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Updated, MapToResource(message.Album, true));
|
BroadcastResourceChange(ModelAction.Updated, MapToResource(message.Album, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(TrackImportedEvent message)
|
public void Handle(TrackImportedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Updated, message.TrackInfo.Album.ToResource());
|
BroadcastResourceChange(ModelAction.Updated, message.TrackInfo.Album.ToResource());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(TrackFileDeletedEvent message)
|
public void Handle(TrackFileDeletedEvent message)
|
||||||
{
|
{
|
||||||
if (message.Reason == DeleteMediaFileReason.Upgrade)
|
if (message.Reason == DeleteMediaFileReason.Upgrade)
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Api.V1.Artist;
|
using Lidarr.Api.V1.Artist;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http.REST;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.ArtistStats;
|
using NzbDrone.Core.ArtistStats;
|
||||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||||
|
@ -11,14 +11,14 @@ using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Albums
|
namespace Lidarr.Api.V1.Albums
|
||||||
{
|
{
|
||||||
public abstract class AlbumModuleWithSignalR : LidarrRestModuleWithSignalR<AlbumResource, Album>
|
public abstract class AlbumControllerWithSignalR : RestControllerWithSignalR<AlbumResource, Album>
|
||||||
{
|
{
|
||||||
protected readonly IAlbumService _albumService;
|
protected readonly IAlbumService _albumService;
|
||||||
protected readonly IArtistStatisticsService _artistStatisticsService;
|
protected readonly IArtistStatisticsService _artistStatisticsService;
|
||||||
protected readonly IUpgradableSpecification _qualityUpgradableSpecification;
|
protected readonly IUpgradableSpecification _qualityUpgradableSpecification;
|
||||||
protected readonly IMapCoversToLocal _coverMapper;
|
protected readonly IMapCoversToLocal _coverMapper;
|
||||||
|
|
||||||
protected AlbumModuleWithSignalR(IAlbumService albumService,
|
protected AlbumControllerWithSignalR(IAlbumService albumService,
|
||||||
IArtistStatisticsService artistStatisticsService,
|
IArtistStatisticsService artistStatisticsService,
|
||||||
IMapCoversToLocal coverMapper,
|
IMapCoversToLocal coverMapper,
|
||||||
IUpgradableSpecification qualityUpgradableSpecification,
|
IUpgradableSpecification qualityUpgradableSpecification,
|
||||||
|
@ -29,27 +29,9 @@ namespace Lidarr.Api.V1.Albums
|
||||||
_artistStatisticsService = artistStatisticsService;
|
_artistStatisticsService = artistStatisticsService;
|
||||||
_coverMapper = coverMapper;
|
_coverMapper = coverMapper;
|
||||||
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||||
|
|
||||||
GetResourceById = GetAlbum;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AlbumModuleWithSignalR(IAlbumService albumService,
|
public override AlbumResource GetResourceById(int id)
|
||||||
IArtistStatisticsService artistStatisticsService,
|
|
||||||
IMapCoversToLocal coverMapper,
|
|
||||||
IUpgradableSpecification qualityUpgradableSpecification,
|
|
||||||
IBroadcastSignalRMessage signalRBroadcaster,
|
|
||||||
string resource)
|
|
||||||
: base(signalRBroadcaster, resource)
|
|
||||||
{
|
|
||||||
_albumService = albumService;
|
|
||||||
_artistStatisticsService = artistStatisticsService;
|
|
||||||
_coverMapper = coverMapper;
|
|
||||||
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
|
||||||
|
|
||||||
GetResourceById = GetAlbum;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AlbumResource GetAlbum(int id)
|
|
||||||
{
|
{
|
||||||
var album = _albumService.GetAlbum(id);
|
var album = _albumService.GetAlbum(id);
|
||||||
var resource = MapToResource(album, true);
|
var resource = MapToResource(album, true);
|
|
@ -1,26 +1,26 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Nancy;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.MediaCover;
|
using NzbDrone.Core.MediaCover;
|
||||||
using NzbDrone.Core.MetadataSource;
|
using NzbDrone.Core.MetadataSource;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Albums
|
namespace Lidarr.Api.V1.Albums
|
||||||
{
|
{
|
||||||
public class AlbumLookupModule : LidarrRestModule<AlbumResource>
|
[V1ApiController("album/lookup")]
|
||||||
|
public class AlbumLookupController : Controller
|
||||||
{
|
{
|
||||||
private readonly ISearchForNewAlbum _searchProxy;
|
private readonly ISearchForNewAlbum _searchProxy;
|
||||||
|
|
||||||
public AlbumLookupModule(ISearchForNewAlbum searchProxy)
|
public AlbumLookupController(ISearchForNewAlbum searchProxy)
|
||||||
: base("/album/lookup")
|
|
||||||
{
|
{
|
||||||
_searchProxy = searchProxy;
|
_searchProxy = searchProxy;
|
||||||
Get("/", x => Search());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private object Search()
|
[HttpGet]
|
||||||
|
public object Search(string term)
|
||||||
{
|
{
|
||||||
var searchResults = _searchProxy.SearchForNewAlbum((string)Request.Query.term, null);
|
var searchResults = _searchProxy.SearchForNewAlbum(term, null);
|
||||||
return MapToResource(searchResults).ToList();
|
return MapToResource(searchResults).ToList();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,9 @@ using System.Linq;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.Extensions;
|
using Lidarr.Http.Extensions;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.ArtistStats;
|
using NzbDrone.Core.ArtistStats;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
using NzbDrone.Core.Datastore.Events;
|
||||||
|
@ -22,7 +25,8 @@ using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Artist
|
namespace Lidarr.Api.V1.Artist
|
||||||
{
|
{
|
||||||
public class ArtistModule : LidarrRestModuleWithSignalR<ArtistResource, NzbDrone.Core.Music.Artist>,
|
[V1ApiController]
|
||||||
|
public class ArtistController : RestControllerWithSignalR<ArtistResource, NzbDrone.Core.Music.Artist>,
|
||||||
IHandle<AlbumImportedEvent>,
|
IHandle<AlbumImportedEvent>,
|
||||||
IHandle<AlbumEditedEvent>,
|
IHandle<AlbumEditedEvent>,
|
||||||
IHandle<AlbumDeletedEvent>,
|
IHandle<AlbumDeletedEvent>,
|
||||||
|
@ -41,7 +45,7 @@ namespace Lidarr.Api.V1.Artist
|
||||||
private readonly IManageCommandQueue _commandQueueManager;
|
private readonly IManageCommandQueue _commandQueueManager;
|
||||||
private readonly IRootFolderService _rootFolderService;
|
private readonly IRootFolderService _rootFolderService;
|
||||||
|
|
||||||
public ArtistModule(IBroadcastSignalRMessage signalRBroadcaster,
|
public ArtistController(IBroadcastSignalRMessage signalRBroadcaster,
|
||||||
IArtistService artistService,
|
IArtistService artistService,
|
||||||
IAlbumService albumService,
|
IAlbumService albumService,
|
||||||
IAddArtistService addArtistService,
|
IAddArtistService addArtistService,
|
||||||
|
@ -68,12 +72,6 @@ namespace Lidarr.Api.V1.Artist
|
||||||
_commandQueueManager = commandQueueManager;
|
_commandQueueManager = commandQueueManager;
|
||||||
_rootFolderService = rootFolderService;
|
_rootFolderService = rootFolderService;
|
||||||
|
|
||||||
GetResourceAll = AllArtists;
|
|
||||||
GetResourceById = GetArtist;
|
|
||||||
CreateResource = AddArtist;
|
|
||||||
UpdateResource = UpdateArtist;
|
|
||||||
DeleteResource = DeleteArtist;
|
|
||||||
|
|
||||||
Http.Validation.RuleBuilderExtensions.ValidId(SharedValidator.RuleFor(s => s.QualityProfileId));
|
Http.Validation.RuleBuilderExtensions.ValidId(SharedValidator.RuleFor(s => s.QualityProfileId));
|
||||||
Http.Validation.RuleBuilderExtensions.ValidId(SharedValidator.RuleFor(s => s.MetadataProfileId));
|
Http.Validation.RuleBuilderExtensions.ValidId(SharedValidator.RuleFor(s => s.MetadataProfileId));
|
||||||
|
|
||||||
|
@ -98,7 +96,7 @@ namespace Lidarr.Api.V1.Artist
|
||||||
PutValidator.RuleFor(s => s.Path).IsValidPath();
|
PutValidator.RuleFor(s => s.Path).IsValidPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArtistResource GetArtist(int id)
|
public override ArtistResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
var artist = _artistService.GetArtist(id);
|
var artist = _artistService.GetArtist(id);
|
||||||
return GetArtistResource(artist);
|
return GetArtistResource(artist);
|
||||||
|
@ -122,15 +120,15 @@ namespace Lidarr.Api.V1.Artist
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ArtistResource> AllArtists()
|
[HttpGet]
|
||||||
|
public List<ArtistResource> AllArtists(Guid? mbId)
|
||||||
{
|
{
|
||||||
var mbId = Request.GetGuidQueryParameter("mbId");
|
|
||||||
var artistStats = _artistStatisticsService.ArtistStatistics();
|
var artistStats = _artistStatisticsService.ArtistStatistics();
|
||||||
var artistsResources = new List<ArtistResource>();
|
var artistsResources = new List<ArtistResource>();
|
||||||
|
|
||||||
if (mbId != Guid.Empty)
|
if (mbId.HasValue)
|
||||||
{
|
{
|
||||||
artistsResources.AddIfNotNull(_artistService.FindById(mbId.ToString()).ToResource());
|
artistsResources.AddIfNotNull(_artistService.FindById(mbId.Value.ToString()).ToResource());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -146,14 +144,16 @@ namespace Lidarr.Api.V1.Artist
|
||||||
return artistsResources;
|
return artistsResources;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int AddArtist(ArtistResource artistResource)
|
[RestPostById]
|
||||||
|
public ActionResult<ArtistResource> AddArtist(ArtistResource artistResource)
|
||||||
{
|
{
|
||||||
var artist = _addArtistService.AddArtist(artistResource.ToModel());
|
var artist = _addArtistService.AddArtist(artistResource.ToModel());
|
||||||
|
|
||||||
return artist.Id;
|
return Created(artist.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateArtist(ArtistResource artistResource)
|
[RestPutById]
|
||||||
|
public ActionResult<ArtistResource> UpdateArtist(ArtistResource artistResource)
|
||||||
{
|
{
|
||||||
var moveFiles = Request.GetBooleanQueryParameter("moveFiles");
|
var moveFiles = Request.GetBooleanQueryParameter("moveFiles");
|
||||||
var artist = _artistService.GetArtist(artistResource.Id);
|
var artist = _artistService.GetArtist(artistResource.Id);
|
||||||
|
@ -175,9 +175,12 @@ namespace Lidarr.Api.V1.Artist
|
||||||
_artistService.UpdateArtist(model);
|
_artistService.UpdateArtist(model);
|
||||||
|
|
||||||
BroadcastResourceChange(ModelAction.Updated, artistResource);
|
BroadcastResourceChange(ModelAction.Updated, artistResource);
|
||||||
|
|
||||||
|
return Accepted(artistResource.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteArtist(int id)
|
[RestDeleteById]
|
||||||
|
public void DeleteArtist(int id)
|
||||||
{
|
{
|
||||||
var deleteFiles = Request.GetBooleanQueryParameter("deleteFiles");
|
var deleteFiles = Request.GetBooleanQueryParameter("deleteFiles");
|
||||||
var addImportListExclusion = Request.GetBooleanQueryParameter("addImportListExclusion");
|
var addImportListExclusion = Request.GetBooleanQueryParameter("addImportListExclusion");
|
||||||
|
@ -250,21 +253,25 @@ namespace Lidarr.Api.V1.Artist
|
||||||
resource.RootFolderPath = _rootFolderService.GetBestRootFolderPath(resource.Path);
|
resource.RootFolderPath = _rootFolderService.GetBestRootFolderPath(resource.Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(AlbumImportedEvent message)
|
public void Handle(AlbumImportedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.Artist));
|
BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.Artist));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(AlbumEditedEvent message)
|
public void Handle(AlbumEditedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.Album.Artist.Value));
|
BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.Album.Artist.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(AlbumDeletedEvent message)
|
public void Handle(AlbumDeletedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.Album.Artist.Value));
|
BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.Album.Artist.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(TrackFileDeletedEvent message)
|
public void Handle(TrackFileDeletedEvent message)
|
||||||
{
|
{
|
||||||
if (message.Reason == DeleteMediaFileReason.Upgrade)
|
if (message.Reason == DeleteMediaFileReason.Upgrade)
|
||||||
|
@ -275,16 +282,19 @@ namespace Lidarr.Api.V1.Artist
|
||||||
BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.TrackFile.Artist.Value));
|
BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.TrackFile.Artist.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(ArtistUpdatedEvent message)
|
public void Handle(ArtistUpdatedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.Artist));
|
BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.Artist));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(ArtistEditedEvent message)
|
public void Handle(ArtistEditedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.Artist));
|
BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.Artist));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(ArtistsDeletedEvent message)
|
public void Handle(ArtistsDeletedEvent message)
|
||||||
{
|
{
|
||||||
foreach (var artist in message.Artists)
|
foreach (var artist in message.Artists)
|
||||||
|
@ -293,11 +303,13 @@ namespace Lidarr.Api.V1.Artist
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(ArtistRenamedEvent message)
|
public void Handle(ArtistRenamedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Updated, message.Artist.Id);
|
BroadcastResourceChange(ModelAction.Updated, message.Artist.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(MediaCoversUpdatedEvent message)
|
public void Handle(MediaCoversUpdatedEvent message)
|
||||||
{
|
{
|
||||||
if (message.Updated)
|
if (message.Updated)
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http.Extensions;
|
using Lidarr.Http;
|
||||||
using Nancy;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Messaging.Commands;
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
|
@ -9,23 +9,21 @@ using NzbDrone.Core.Music.Commands;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Artist
|
namespace Lidarr.Api.V1.Artist
|
||||||
{
|
{
|
||||||
public class ArtistEditorModule : LidarrV1Module
|
[V1ApiController("artist/editor")]
|
||||||
|
public class ArtistEditorController : Controller
|
||||||
{
|
{
|
||||||
private readonly IArtistService _artistService;
|
private readonly IArtistService _artistService;
|
||||||
private readonly IManageCommandQueue _commandQueueManager;
|
private readonly IManageCommandQueue _commandQueueManager;
|
||||||
|
|
||||||
public ArtistEditorModule(IArtistService artistService, IManageCommandQueue commandQueueManager)
|
public ArtistEditorController(IArtistService artistService, IManageCommandQueue commandQueueManager)
|
||||||
: base("/artist/editor")
|
|
||||||
{
|
{
|
||||||
_artistService = artistService;
|
_artistService = artistService;
|
||||||
_commandQueueManager = commandQueueManager;
|
_commandQueueManager = commandQueueManager;
|
||||||
Put("/", artist => SaveAll());
|
|
||||||
Delete("/", artist => DeleteArtist());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private object SaveAll()
|
[HttpPut]
|
||||||
|
public IActionResult SaveAll([FromBody] ArtistEditorResource resource)
|
||||||
{
|
{
|
||||||
var resource = Request.Body.FromJson<ArtistEditorResource>();
|
|
||||||
var artistToUpdate = _artistService.GetArtists(resource.ArtistIds);
|
var artistToUpdate = _artistService.GetArtists(resource.ArtistIds);
|
||||||
var artistToMove = new List<BulkMoveArtist>();
|
var artistToMove = new List<BulkMoveArtist>();
|
||||||
|
|
||||||
|
@ -86,15 +84,12 @@ namespace Lidarr.Api.V1.Artist
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResponseWithCode(_artistService.UpdateArtists(artistToUpdate, !resource.MoveFiles)
|
return Accepted(_artistService.UpdateArtists(artistToUpdate, !resource.MoveFiles).ToResource());
|
||||||
.ToResource(),
|
|
||||||
HttpStatusCode.Accepted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private object DeleteArtist()
|
[HttpDelete]
|
||||||
|
public object DeleteArtist([FromBody] ArtistEditorResource resource)
|
||||||
{
|
{
|
||||||
var resource = Request.Body.FromJson<ArtistEditorResource>();
|
|
||||||
|
|
||||||
_artistService.DeleteArtists(resource.ArtistIds, resource.DeleteFiles);
|
_artistService.DeleteArtists(resource.ArtistIds, resource.DeleteFiles);
|
||||||
|
|
||||||
return new object();
|
return new object();
|
|
@ -1,28 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using Lidarr.Http;
|
|
||||||
using Lidarr.Http.Extensions;
|
|
||||||
using Nancy;
|
|
||||||
using NzbDrone.Core.Music;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Artist
|
|
||||||
{
|
|
||||||
public class ArtistImportModule : LidarrRestModule<ArtistResource>
|
|
||||||
{
|
|
||||||
private readonly IAddArtistService _addArtistService;
|
|
||||||
|
|
||||||
public ArtistImportModule(IAddArtistService addArtistService)
|
|
||||||
: base("/artist/import")
|
|
||||||
{
|
|
||||||
_addArtistService = addArtistService;
|
|
||||||
Post("/", x => Import());
|
|
||||||
}
|
|
||||||
|
|
||||||
private object Import()
|
|
||||||
{
|
|
||||||
var resource = Request.Body.FromJson<List<ArtistResource>>();
|
|
||||||
var newArtists = resource.ToModel();
|
|
||||||
|
|
||||||
return _addArtistService.AddArtists(newArtists).ToResource();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +1,26 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Nancy;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.MediaCover;
|
using NzbDrone.Core.MediaCover;
|
||||||
using NzbDrone.Core.MetadataSource;
|
using NzbDrone.Core.MetadataSource;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Artist
|
namespace Lidarr.Api.V1.Artist
|
||||||
{
|
{
|
||||||
public class ArtistLookupModule : LidarrRestModule<ArtistResource>
|
[V1ApiController("artist/lookup")]
|
||||||
|
public class ArtistLookupController : Controller
|
||||||
{
|
{
|
||||||
private readonly ISearchForNewArtist _searchProxy;
|
private readonly ISearchForNewArtist _searchProxy;
|
||||||
|
|
||||||
public ArtistLookupModule(ISearchForNewArtist searchProxy)
|
public ArtistLookupController(ISearchForNewArtist searchProxy)
|
||||||
: base("/artist/lookup")
|
|
||||||
{
|
{
|
||||||
_searchProxy = searchProxy;
|
_searchProxy = searchProxy;
|
||||||
Get("/", x => Search());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private object Search()
|
[HttpGet]
|
||||||
|
public object Search([FromQuery] string term)
|
||||||
{
|
{
|
||||||
var searchResults = _searchProxy.SearchForNewArtist((string)Request.Query.term);
|
var searchResults = _searchProxy.SearchForNewArtist(term);
|
||||||
return MapToResource(searchResults).ToList();
|
return MapToResource(searchResults).ToList();
|
||||||
}
|
}
|
||||||
|
|
43
src/Lidarr.Api.V1/Blacklist/BlacklistController.cs
Normal file
43
src/Lidarr.Api.V1/Blacklist/BlacklistController.cs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.Extensions;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NzbDrone.Core.Blacklisting;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
|
||||||
|
namespace Lidarr.Api.V1.Blacklist
|
||||||
|
{
|
||||||
|
[V1ApiController]
|
||||||
|
public class BlacklistController : Controller
|
||||||
|
{
|
||||||
|
private readonly IBlacklistService _blacklistService;
|
||||||
|
|
||||||
|
public BlacklistController(IBlacklistService blacklistService)
|
||||||
|
{
|
||||||
|
_blacklistService = blacklistService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public PagingResource<BlacklistResource> GetBlacklist()
|
||||||
|
{
|
||||||
|
var pagingResource = Request.ReadPagingResourceFromRequest<BlacklistResource>();
|
||||||
|
var pagingSpec = pagingResource.MapToPagingSpec<BlacklistResource, NzbDrone.Core.Blacklisting.Blacklist>("date", SortDirection.Descending);
|
||||||
|
|
||||||
|
return pagingSpec.ApplyToPage(_blacklistService.Paged, BlacklistResourceMapper.MapToResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RestDeleteById]
|
||||||
|
public void DeleteBlacklist(int id)
|
||||||
|
{
|
||||||
|
_blacklistService.Delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("bulk")]
|
||||||
|
public object Remove([FromBody] BlacklistBulkResource resource)
|
||||||
|
{
|
||||||
|
_blacklistService.Delete(resource.Ids);
|
||||||
|
|
||||||
|
return new object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,42 +0,0 @@
|
||||||
using Lidarr.Http;
|
|
||||||
using Lidarr.Http.Extensions;
|
|
||||||
using NzbDrone.Core.Blacklisting;
|
|
||||||
using NzbDrone.Core.Datastore;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Blacklist
|
|
||||||
{
|
|
||||||
public class BlacklistModule : LidarrRestModule<BlacklistResource>
|
|
||||||
{
|
|
||||||
private readonly IBlacklistService _blacklistService;
|
|
||||||
|
|
||||||
public BlacklistModule(IBlacklistService blacklistService)
|
|
||||||
{
|
|
||||||
_blacklistService = blacklistService;
|
|
||||||
GetResourcePaged = GetBlacklist;
|
|
||||||
DeleteResource = DeleteBlacklist;
|
|
||||||
|
|
||||||
Delete("/bulk", x => Remove());
|
|
||||||
}
|
|
||||||
|
|
||||||
private PagingResource<BlacklistResource> GetBlacklist(PagingResource<BlacklistResource> pagingResource)
|
|
||||||
{
|
|
||||||
var pagingSpec = pagingResource.MapToPagingSpec<BlacklistResource, NzbDrone.Core.Blacklisting.Blacklist>("date", SortDirection.Descending);
|
|
||||||
|
|
||||||
return ApplyToPage(_blacklistService.Paged, pagingSpec, BlacklistResourceMapper.MapToResource);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DeleteBlacklist(int id)
|
|
||||||
{
|
|
||||||
_blacklistService.Delete(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
private object Remove()
|
|
||||||
{
|
|
||||||
var resource = Request.Body.FromJson<BlacklistBulkResource>();
|
|
||||||
|
|
||||||
_blacklistService.Delete(resource.Ids);
|
|
||||||
|
|
||||||
return new object();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
42
src/Lidarr.Api.V1/Calendar/CalendarController.cs
Normal file
42
src/Lidarr.Api.V1/Calendar/CalendarController.cs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Lidarr.Api.V1.Albums;
|
||||||
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.Extensions;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NzbDrone.Core.ArtistStats;
|
||||||
|
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||||
|
using NzbDrone.Core.MediaCover;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
using NzbDrone.SignalR;
|
||||||
|
|
||||||
|
namespace Lidarr.Api.V1.Calendar
|
||||||
|
{
|
||||||
|
[V1ApiController]
|
||||||
|
public class CalendarController : AlbumControllerWithSignalR
|
||||||
|
{
|
||||||
|
public CalendarController(IAlbumService albumService,
|
||||||
|
IArtistStatisticsService artistStatisticsService,
|
||||||
|
IMapCoversToLocal coverMapper,
|
||||||
|
IUpgradableSpecification upgradableSpecification,
|
||||||
|
IBroadcastSignalRMessage signalRBroadcaster)
|
||||||
|
: base(albumService, artistStatisticsService, coverMapper, upgradableSpecification, signalRBroadcaster)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public List<AlbumResource> GetCalendar(DateTime? start, DateTime? end, bool unmonitored = false, bool includeArtist = false)
|
||||||
|
{
|
||||||
|
//TODO: Add Album Image support to AlbumControllerWithSignalR
|
||||||
|
var includeAlbumImages = Request.GetBooleanQueryParameter("includeAlbumImages");
|
||||||
|
|
||||||
|
var startUse = start ?? DateTime.Today;
|
||||||
|
var endUse = end ?? DateTime.Today.AddDays(2);
|
||||||
|
|
||||||
|
var resources = MapToResource(_albumService.AlbumsBetweenDates(startUse, endUse, unmonitored), includeArtist);
|
||||||
|
|
||||||
|
return resources.OrderBy(e => e.ReleaseDate).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,60 +5,38 @@ using Ical.Net;
|
||||||
using Ical.Net.CalendarComponents;
|
using Ical.Net.CalendarComponents;
|
||||||
using Ical.Net.DataTypes;
|
using Ical.Net.DataTypes;
|
||||||
using Ical.Net.Serialization;
|
using Ical.Net.Serialization;
|
||||||
using Lidarr.Http.Extensions;
|
using Lidarr.Http;
|
||||||
using Nancy;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Nancy.Responses;
|
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
using NzbDrone.Core.Tags;
|
using NzbDrone.Core.Tags;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Calendar
|
namespace Lidarr.Api.V1.Calendar
|
||||||
{
|
{
|
||||||
public class CalendarFeedModule : LidarrV1FeedModule
|
[V1FeedController("calendar")]
|
||||||
|
public class CalendarFeedController : Controller
|
||||||
{
|
{
|
||||||
private readonly IAlbumService _albumService;
|
private readonly IAlbumService _albumService;
|
||||||
private readonly IArtistService _artistService;
|
private readonly IArtistService _artistService;
|
||||||
private readonly ITagService _tagService;
|
private readonly ITagService _tagService;
|
||||||
|
|
||||||
public CalendarFeedModule(IAlbumService albumService, IArtistService artistService, ITagService tagService)
|
public CalendarFeedController(IAlbumService albumService, IArtistService artistService, ITagService tagService)
|
||||||
: base("calendar")
|
|
||||||
{
|
{
|
||||||
_albumService = albumService;
|
_albumService = albumService;
|
||||||
_artistService = artistService;
|
_artistService = artistService;
|
||||||
_tagService = tagService;
|
_tagService = tagService;
|
||||||
|
|
||||||
Get("/Lidarr.ics", options => GetCalendarFeed());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private object GetCalendarFeed()
|
[HttpGet("Lidarr.ics")]
|
||||||
|
public IActionResult GetCalendarFeed(int pastDays = 7, int futureDays = 28, string tagList = "", bool unmonitored = false)
|
||||||
{
|
{
|
||||||
var pastDays = 7;
|
|
||||||
var futureDays = 28;
|
|
||||||
var start = DateTime.Today.AddDays(-pastDays);
|
var start = DateTime.Today.AddDays(-pastDays);
|
||||||
var end = DateTime.Today.AddDays(futureDays);
|
var end = DateTime.Today.AddDays(futureDays);
|
||||||
var unmonitored = Request.GetBooleanQueryParameter("unmonitored");
|
|
||||||
var tags = new List<int>();
|
var tags = new List<int>();
|
||||||
|
|
||||||
var queryPastDays = Request.Query.PastDays;
|
if (tagList.IsNotNullOrWhiteSpace())
|
||||||
var queryFutureDays = Request.Query.FutureDays;
|
|
||||||
var queryTags = Request.Query.Tags;
|
|
||||||
|
|
||||||
if (queryPastDays.HasValue)
|
|
||||||
{
|
{
|
||||||
pastDays = int.Parse(queryPastDays.Value);
|
tags.AddRange(tagList.Split(',').Select(_tagService.GetTag).Select(t => t.Id));
|
||||||
start = DateTime.Today.AddDays(-pastDays);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queryFutureDays.HasValue)
|
|
||||||
{
|
|
||||||
futureDays = int.Parse(queryFutureDays.Value);
|
|
||||||
end = DateTime.Today.AddDays(futureDays);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queryTags.HasValue)
|
|
||||||
{
|
|
||||||
var tagInput = (string)queryTags.Value.ToString();
|
|
||||||
tags.AddRange(tagInput.Split(',').Select(_tagService.GetTag).Select(t => t.Id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var albums = _albumService.AlbumsBetweenDates(start, end, unmonitored);
|
var albums = _albumService.AlbumsBetweenDates(start, end, unmonitored);
|
||||||
|
@ -95,7 +73,7 @@ namespace Lidarr.Api.V1.Calendar
|
||||||
var serializer = (IStringSerializer)new SerializerFactory().Build(calendar.GetType(), new SerializationContext());
|
var serializer = (IStringSerializer)new SerializerFactory().Build(calendar.GetType(), new SerializationContext());
|
||||||
var icalendar = serializer.SerializeToString(calendar);
|
var icalendar = serializer.SerializeToString(calendar);
|
||||||
|
|
||||||
return new TextResponse(icalendar, "text/calendar");
|
return Content(icalendar, "text/calendar");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,54 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Lidarr.Api.V1.Albums;
|
|
||||||
using Lidarr.Http.Extensions;
|
|
||||||
using NzbDrone.Core.ArtistStats;
|
|
||||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
|
||||||
using NzbDrone.Core.MediaCover;
|
|
||||||
using NzbDrone.Core.Music;
|
|
||||||
using NzbDrone.SignalR;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Calendar
|
|
||||||
{
|
|
||||||
public class CalendarModule : AlbumModuleWithSignalR
|
|
||||||
{
|
|
||||||
public CalendarModule(IAlbumService albumService,
|
|
||||||
IArtistStatisticsService artistStatisticsService,
|
|
||||||
IMapCoversToLocal coverMapper,
|
|
||||||
IUpgradableSpecification upgradableSpecification,
|
|
||||||
IBroadcastSignalRMessage signalRBroadcaster)
|
|
||||||
: base(albumService, artistStatisticsService, coverMapper, upgradableSpecification, signalRBroadcaster, "calendar")
|
|
||||||
{
|
|
||||||
GetResourceAll = GetCalendar;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<AlbumResource> GetCalendar()
|
|
||||||
{
|
|
||||||
var start = DateTime.Today;
|
|
||||||
var end = DateTime.Today.AddDays(2);
|
|
||||||
var includeUnmonitored = Request.GetBooleanQueryParameter("unmonitored");
|
|
||||||
var includeArtist = Request.GetBooleanQueryParameter("includeArtist");
|
|
||||||
|
|
||||||
//TODO: Add Album Image support to AlbumModuleWithSignalR
|
|
||||||
var includeAlbumImages = Request.GetBooleanQueryParameter("includeAlbumImages");
|
|
||||||
|
|
||||||
var queryStart = Request.Query.Start;
|
|
||||||
var queryEnd = Request.Query.End;
|
|
||||||
|
|
||||||
if (queryStart.HasValue)
|
|
||||||
{
|
|
||||||
start = DateTime.Parse(queryStart.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queryEnd.HasValue)
|
|
||||||
{
|
|
||||||
end = DateTime.Parse(queryEnd.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
var resources = MapToResource(_albumService.AlbumsBetweenDates(start, end, includeUnmonitored), includeArtist);
|
|
||||||
|
|
||||||
return resources.OrderBy(e => e.ReleaseDate).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +1,14 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.Extensions;
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
using Lidarr.Http.Validation;
|
using Lidarr.Http.Validation;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common;
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Common.Serializer;
|
||||||
using NzbDrone.Common.TPL;
|
using NzbDrone.Common.TPL;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
using NzbDrone.Core.Datastore.Events;
|
||||||
using NzbDrone.Core.Messaging.Commands;
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
@ -14,14 +18,15 @@ using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Commands
|
namespace Lidarr.Api.V1.Commands
|
||||||
{
|
{
|
||||||
public class CommandModule : LidarrRestModuleWithSignalR<CommandResource, CommandModel>, IHandle<CommandUpdatedEvent>
|
[V1ApiController]
|
||||||
|
public class CommandController : RestControllerWithSignalR<CommandResource, CommandModel>, IHandle<CommandUpdatedEvent>
|
||||||
{
|
{
|
||||||
private readonly IManageCommandQueue _commandQueueManager;
|
private readonly IManageCommandQueue _commandQueueManager;
|
||||||
private readonly IServiceFactory _serviceFactory;
|
private readonly IServiceFactory _serviceFactory;
|
||||||
private readonly Debouncer _debouncer;
|
private readonly Debouncer _debouncer;
|
||||||
private readonly Dictionary<int, CommandResource> _pendingUpdates;
|
private readonly Dictionary<int, CommandResource> _pendingUpdates;
|
||||||
|
|
||||||
public CommandModule(IManageCommandQueue commandQueueManager,
|
public CommandController(IManageCommandQueue commandQueueManager,
|
||||||
IBroadcastSignalRMessage signalRBroadcaster,
|
IBroadcastSignalRMessage signalRBroadcaster,
|
||||||
IServiceFactory serviceFactory)
|
IServiceFactory serviceFactory)
|
||||||
: base(signalRBroadcaster)
|
: base(signalRBroadcaster)
|
||||||
|
@ -29,50 +34,55 @@ namespace Lidarr.Api.V1.Commands
|
||||||
_commandQueueManager = commandQueueManager;
|
_commandQueueManager = commandQueueManager;
|
||||||
_serviceFactory = serviceFactory;
|
_serviceFactory = serviceFactory;
|
||||||
|
|
||||||
GetResourceById = GetCommand;
|
|
||||||
CreateResource = StartCommand;
|
|
||||||
GetResourceAll = GetStartedCommands;
|
|
||||||
DeleteResource = CancelCommand;
|
|
||||||
|
|
||||||
PostValidator.RuleFor(c => c.Name).NotBlank();
|
PostValidator.RuleFor(c => c.Name).NotBlank();
|
||||||
|
|
||||||
_debouncer = new Debouncer(SendUpdates, TimeSpan.FromSeconds(0.1));
|
_debouncer = new Debouncer(SendUpdates, TimeSpan.FromSeconds(0.1));
|
||||||
_pendingUpdates = new Dictionary<int, CommandResource>();
|
_pendingUpdates = new Dictionary<int, CommandResource>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private CommandResource GetCommand(int id)
|
public override CommandResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
return _commandQueueManager.Get(id).ToResource();
|
return _commandQueueManager.Get(id).ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int StartCommand(CommandResource commandResource)
|
[RestPostById]
|
||||||
|
public ActionResult<CommandResource> StartCommand(CommandResource commandResource)
|
||||||
{
|
{
|
||||||
var commandType =
|
var commandType =
|
||||||
_serviceFactory.GetImplementations(typeof(Command))
|
_serviceFactory.GetImplementations(typeof(Command))
|
||||||
.Single(c => c.Name.Replace("Command", "")
|
.Single(c => c.Name.Replace("Command", "")
|
||||||
.Equals(commandResource.Name, StringComparison.InvariantCultureIgnoreCase));
|
.Equals(commandResource.Name, StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
|
||||||
dynamic command = Request.Body.FromJson(commandType);
|
Request.Body.Seek(0, SeekOrigin.Begin);
|
||||||
|
using (var reader = new StreamReader(Request.Body))
|
||||||
|
{
|
||||||
|
var body = reader.ReadToEnd();
|
||||||
|
|
||||||
|
dynamic command = STJson.Deserialize(body, commandType);
|
||||||
|
|
||||||
command.Trigger = CommandTrigger.Manual;
|
command.Trigger = CommandTrigger.Manual;
|
||||||
command.SuppressMessages = !command.SendUpdatesToClient;
|
command.SuppressMessages = !command.SendUpdatesToClient;
|
||||||
command.SendUpdatesToClient = true;
|
command.SendUpdatesToClient = true;
|
||||||
|
command.ClientUserAgent = Request.Headers["UserAgent"];
|
||||||
command.ClientUserAgent = Request.Headers.UserAgent;
|
|
||||||
|
|
||||||
var trackedCommand = _commandQueueManager.Push(command, CommandPriority.Normal, CommandTrigger.Manual);
|
var trackedCommand = _commandQueueManager.Push(command, CommandPriority.Normal, CommandTrigger.Manual);
|
||||||
return trackedCommand.Id;
|
return Created(trackedCommand.Id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<CommandResource> GetStartedCommands()
|
[HttpGet]
|
||||||
|
public List<CommandResource> GetStartedCommands()
|
||||||
{
|
{
|
||||||
return _commandQueueManager.All().ToResource();
|
return _commandQueueManager.All().ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CancelCommand(int id)
|
[RestDeleteById]
|
||||||
|
public void CancelCommand(int id)
|
||||||
{
|
{
|
||||||
_commandQueueManager.Cancel(id);
|
_commandQueueManager.Cancel(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(CommandUpdatedEvent message)
|
public void Handle(CommandUpdatedEvent message)
|
||||||
{
|
{
|
||||||
if (message.Command.Body.SendUpdatesToClient)
|
if (message.Command.Body.SendUpdatesToClient)
|
48
src/Lidarr.Api.V1/Config/ConfigController.cs
Normal file
48
src/Lidarr.Api.V1/Config/ConfigController.cs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
|
||||||
|
namespace Lidarr.Api.V1.Config
|
||||||
|
{
|
||||||
|
public abstract class ConfigController<TResource> : RestController<TResource>
|
||||||
|
where TResource : RestResource, new()
|
||||||
|
{
|
||||||
|
private readonly IConfigService _configService;
|
||||||
|
|
||||||
|
protected ConfigController(IConfigService configService)
|
||||||
|
{
|
||||||
|
_configService = configService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override TResource GetResourceById(int id)
|
||||||
|
{
|
||||||
|
return GetConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public TResource GetConfig()
|
||||||
|
{
|
||||||
|
var resource = ToResource(_configService);
|
||||||
|
resource.Id = 1;
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RestPutById]
|
||||||
|
public ActionResult<TResource> SaveConfig(TResource resource)
|
||||||
|
{
|
||||||
|
var dictionary = resource.GetType()
|
||||||
|
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||||
|
.ToDictionary(prop => prop.Name, prop => prop.GetValue(resource, null));
|
||||||
|
|
||||||
|
_configService.SaveConfigDictionary(dictionary);
|
||||||
|
|
||||||
|
return Accepted(resource.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract TResource ToResource(IConfigService model);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,12 @@
|
||||||
|
using Lidarr.Http;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Config
|
namespace Lidarr.Api.V1.Config
|
||||||
{
|
{
|
||||||
public class DownloadClientConfigModule : LidarrConfigModule<DownloadClientConfigResource>
|
[V1ApiController("config/downloadclient")]
|
||||||
|
public class DownloadClientConfigController : ConfigController<DownloadClientConfigResource>
|
||||||
{
|
{
|
||||||
public DownloadClientConfigModule(IConfigService configService)
|
public DownloadClientConfigController(IConfigService configService)
|
||||||
: base(configService)
|
: base(configService)
|
||||||
{
|
{
|
||||||
}
|
}
|
|
@ -4,6 +4,9 @@ using System.Reflection;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Authentication;
|
using NzbDrone.Core.Authentication;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
|
@ -13,26 +16,22 @@ using NzbDrone.Core.Validation.Paths;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Config
|
namespace Lidarr.Api.V1.Config
|
||||||
{
|
{
|
||||||
public class HostConfigModule : LidarrRestModule<HostConfigResource>
|
[V1ApiController("config/host")]
|
||||||
|
public class HostConfigController : RestController<HostConfigResource>
|
||||||
{
|
{
|
||||||
private readonly IConfigFileProvider _configFileProvider;
|
private readonly IConfigFileProvider _configFileProvider;
|
||||||
private readonly IConfigService _configService;
|
private readonly IConfigService _configService;
|
||||||
private readonly IUserService _userService;
|
private readonly IUserService _userService;
|
||||||
|
|
||||||
public HostConfigModule(IConfigFileProvider configFileProvider,
|
public HostConfigController(IConfigFileProvider configFileProvider,
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IUserService userService,
|
IUserService userService,
|
||||||
FileExistsValidator fileExistsValidator)
|
FileExistsValidator fileExistsValidator)
|
||||||
: base("/config/host")
|
|
||||||
{
|
{
|
||||||
_configFileProvider = configFileProvider;
|
_configFileProvider = configFileProvider;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_userService = userService;
|
_userService = userService;
|
||||||
|
|
||||||
GetResourceSingle = GetHostConfig;
|
|
||||||
GetResourceById = GetHostConfig;
|
|
||||||
UpdateResource = SaveHostConfig;
|
|
||||||
|
|
||||||
SharedValidator.RuleFor(c => c.BindAddress)
|
SharedValidator.RuleFor(c => c.BindAddress)
|
||||||
.ValidIp4Address()
|
.ValidIp4Address()
|
||||||
.NotListenAllIp4Address()
|
.NotListenAllIp4Address()
|
||||||
|
@ -79,7 +78,13 @@ namespace Lidarr.Api.V1.Config
|
||||||
return cert != null;
|
return cert != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HostConfigResource GetHostConfig()
|
public override HostConfigResource GetResourceById(int id)
|
||||||
|
{
|
||||||
|
return GetHostConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public HostConfigResource GetHostConfig()
|
||||||
{
|
{
|
||||||
var resource = _configFileProvider.ToResource(_configService);
|
var resource = _configFileProvider.ToResource(_configService);
|
||||||
resource.Id = 1;
|
resource.Id = 1;
|
||||||
|
@ -94,12 +99,8 @@ namespace Lidarr.Api.V1.Config
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HostConfigResource GetHostConfig(int id)
|
[RestPutById]
|
||||||
{
|
public ActionResult<HostConfigResource> SaveHostConfig(HostConfigResource resource)
|
||||||
return GetHostConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SaveHostConfig(HostConfigResource resource)
|
|
||||||
{
|
{
|
||||||
var dictionary = resource.GetType()
|
var dictionary = resource.GetType()
|
||||||
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||||
|
@ -112,6 +113,8 @@ namespace Lidarr.Api.V1.Config
|
||||||
{
|
{
|
||||||
_userService.Upsert(resource.Username, resource.Password);
|
_userService.Upsert(resource.Username, resource.Password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Accepted(resource.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,14 @@
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.Validation;
|
using Lidarr.Http.Validation;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Config
|
namespace Lidarr.Api.V1.Config
|
||||||
{
|
{
|
||||||
public class IndexerConfigModule : LidarrConfigModule<IndexerConfigResource>
|
[V1ApiController("config/indexer")]
|
||||||
|
public class IndexerConfigController : ConfigController<IndexerConfigResource>
|
||||||
{
|
{
|
||||||
public IndexerConfigModule(IConfigService configService)
|
public IndexerConfigController(IConfigService configService)
|
||||||
: base(configService)
|
: base(configService)
|
||||||
{
|
{
|
||||||
SharedValidator.RuleFor(c => c.MinimumAge)
|
SharedValidator.RuleFor(c => c.MinimumAge)
|
|
@ -1,53 +0,0 @@
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using Lidarr.Http;
|
|
||||||
using Lidarr.Http.REST;
|
|
||||||
using NzbDrone.Core.Configuration;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Config
|
|
||||||
{
|
|
||||||
public abstract class LidarrConfigModule<TResource> : LidarrRestModule<TResource>
|
|
||||||
where TResource : RestResource, new()
|
|
||||||
{
|
|
||||||
private readonly IConfigService _configService;
|
|
||||||
|
|
||||||
protected LidarrConfigModule(IConfigService configService)
|
|
||||||
: this(new TResource().ResourceName.Replace("config", ""), configService)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected LidarrConfigModule(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,4 +1,5 @@
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
|
using Lidarr.Http;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
|
@ -6,9 +7,10 @@ using NzbDrone.Core.Validation.Paths;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Config
|
namespace Lidarr.Api.V1.Config
|
||||||
{
|
{
|
||||||
public class MediaManagementConfigModule : LidarrConfigModule<MediaManagementConfigResource>
|
[V1ApiController("config/mediamanagement")]
|
||||||
|
public class MediaManagementConfigController : ConfigController<MediaManagementConfigResource>
|
||||||
{
|
{
|
||||||
public MediaManagementConfigModule(IConfigService configService, PathExistsValidator pathExistsValidator, FolderChmodValidator folderChmodValidator)
|
public MediaManagementConfigController(IConfigService configService, PathExistsValidator pathExistsValidator, FolderChmodValidator folderChmodValidator)
|
||||||
: base(configService)
|
: base(configService)
|
||||||
{
|
{
|
||||||
SharedValidator.RuleFor(c => c.RecycleBinCleanupDays).GreaterThanOrEqualTo(0);
|
SharedValidator.RuleFor(c => c.RecycleBinCleanupDays).GreaterThanOrEqualTo(0);
|
|
@ -1,13 +1,15 @@
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
|
using Lidarr.Http;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Config
|
namespace Lidarr.Api.V1.Config
|
||||||
{
|
{
|
||||||
public class MetadataProviderConfigModule : LidarrConfigModule<MetadataProviderConfigResource>
|
[V1ApiController("config/metadataprovider")]
|
||||||
|
public class MetadataProviderConfigController : ConfigController<MetadataProviderConfigResource>
|
||||||
{
|
{
|
||||||
public MetadataProviderConfigModule(IConfigService configService)
|
public MetadataProviderConfigController(IConfigService configService)
|
||||||
: base(configService)
|
: base(configService)
|
||||||
{
|
{
|
||||||
SharedValidator.RuleFor(c => c.MetadataSource).IsValidUrl().When(c => !c.MetadataSource.IsNullOrWhiteSpace());
|
SharedValidator.RuleFor(c => c.MetadataSource).IsValidUrl().When(c => !c.MetadataSource.IsNullOrWhiteSpace());
|
|
@ -3,49 +3,44 @@ using System.Linq;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using FluentValidation.Results;
|
using FluentValidation.Results;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Nancy.ModelBinding;
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Organizer;
|
using NzbDrone.Core.Organizer;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Config
|
namespace Lidarr.Api.V1.Config
|
||||||
{
|
{
|
||||||
public class NamingConfigModule : LidarrRestModule<NamingConfigResource>
|
[V1ApiController("config/naming")]
|
||||||
|
public class NamingConfigController : RestController<NamingConfigResource>
|
||||||
{
|
{
|
||||||
private readonly INamingConfigService _namingConfigService;
|
private readonly INamingConfigService _namingConfigService;
|
||||||
private readonly IFilenameSampleService _filenameSampleService;
|
private readonly IFilenameSampleService _filenameSampleService;
|
||||||
private readonly IFilenameValidationService _filenameValidationService;
|
private readonly IFilenameValidationService _filenameValidationService;
|
||||||
private readonly IBuildFileNames _filenameBuilder;
|
private readonly IBuildFileNames _filenameBuilder;
|
||||||
|
|
||||||
public NamingConfigModule(INamingConfigService namingConfigService,
|
public NamingConfigController(INamingConfigService namingConfigService,
|
||||||
IFilenameSampleService filenameSampleService,
|
IFilenameSampleService filenameSampleService,
|
||||||
IFilenameValidationService filenameValidationService,
|
IFilenameValidationService filenameValidationService,
|
||||||
IBuildFileNames filenameBuilder)
|
IBuildFileNames filenameBuilder)
|
||||||
: base("config/naming")
|
|
||||||
{
|
{
|
||||||
_namingConfigService = namingConfigService;
|
_namingConfigService = namingConfigService;
|
||||||
_filenameSampleService = filenameSampleService;
|
_filenameSampleService = filenameSampleService;
|
||||||
_filenameValidationService = filenameValidationService;
|
_filenameValidationService = filenameValidationService;
|
||||||
_filenameBuilder = filenameBuilder;
|
_filenameBuilder = filenameBuilder;
|
||||||
GetResourceSingle = GetNamingConfig;
|
|
||||||
GetResourceById = GetNamingConfig;
|
|
||||||
UpdateResource = UpdateNamingConfig;
|
|
||||||
|
|
||||||
Get("/examples", x => GetExamples(this.Bind<NamingConfigResource>()));
|
|
||||||
|
|
||||||
SharedValidator.RuleFor(c => c.StandardTrackFormat).ValidTrackFormat();
|
SharedValidator.RuleFor(c => c.StandardTrackFormat).ValidTrackFormat();
|
||||||
SharedValidator.RuleFor(c => c.MultiDiscTrackFormat).ValidTrackFormat();
|
SharedValidator.RuleFor(c => c.MultiDiscTrackFormat).ValidTrackFormat();
|
||||||
SharedValidator.RuleFor(c => c.ArtistFolderFormat).ValidArtistFolderFormat();
|
SharedValidator.RuleFor(c => c.ArtistFolderFormat).ValidArtistFolderFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateNamingConfig(NamingConfigResource resource)
|
public override NamingConfigResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
var nameSpec = resource.ToModel();
|
return GetNamingConfig();
|
||||||
ValidateFormatResult(nameSpec);
|
|
||||||
|
|
||||||
_namingConfigService.Save(nameSpec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private NamingConfigResource GetNamingConfig()
|
[HttpGet]
|
||||||
|
public NamingConfigResource GetNamingConfig()
|
||||||
{
|
{
|
||||||
var nameSpec = _namingConfigService.GetConfig();
|
var nameSpec = _namingConfigService.GetConfig();
|
||||||
var resource = nameSpec.ToResource();
|
var resource = nameSpec.ToResource();
|
||||||
|
@ -65,12 +60,19 @@ namespace Lidarr.Api.V1.Config
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
private NamingConfigResource GetNamingConfig(int id)
|
[RestPutById]
|
||||||
|
public ActionResult<NamingConfigResource> UpdateNamingConfig(NamingConfigResource resource)
|
||||||
{
|
{
|
||||||
return GetNamingConfig();
|
var nameSpec = resource.ToModel();
|
||||||
|
ValidateFormatResult(nameSpec);
|
||||||
|
|
||||||
|
_namingConfigService.Save(nameSpec);
|
||||||
|
|
||||||
|
return Accepted(resource.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private object GetExamples(NamingConfigResource config)
|
[HttpGet("examples")]
|
||||||
|
public object GetExamples([FromQuery]NamingConfigResource config)
|
||||||
{
|
{
|
||||||
if (config.Id == 0)
|
if (config.Id == 0)
|
||||||
{
|
{
|
|
@ -1,10 +1,12 @@
|
||||||
using NzbDrone.Core.Configuration;
|
using Lidarr.Http;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Config
|
namespace Lidarr.Api.V1.Config
|
||||||
{
|
{
|
||||||
public class UiConfigModule : LidarrConfigModule<UiConfigResource>
|
[V1ApiController("config/ui")]
|
||||||
|
public class UiConfigController : ConfigController<UiConfigResource>
|
||||||
{
|
{
|
||||||
public UiConfigModule(IConfigService configService)
|
public UiConfigController(IConfigService configService)
|
||||||
: base(configService)
|
: base(configService)
|
||||||
{
|
{
|
||||||
}
|
}
|
52
src/Lidarr.Api.V1/CustomFilters/CustomFilterController.cs
Normal file
52
src/Lidarr.Api.V1/CustomFilters/CustomFilterController.cs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NzbDrone.Core.CustomFilters;
|
||||||
|
|
||||||
|
namespace Lidarr.Api.V1.CustomFilters
|
||||||
|
{
|
||||||
|
[V1ApiController]
|
||||||
|
public class CustomFilterController : RestController<CustomFilterResource>
|
||||||
|
{
|
||||||
|
private readonly ICustomFilterService _customFilterService;
|
||||||
|
|
||||||
|
public CustomFilterController(ICustomFilterService customFilterService)
|
||||||
|
{
|
||||||
|
_customFilterService = customFilterService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override CustomFilterResource GetResourceById(int id)
|
||||||
|
{
|
||||||
|
return _customFilterService.Get(id).ToResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public List<CustomFilterResource> GetCustomFilters()
|
||||||
|
{
|
||||||
|
return _customFilterService.All().ToResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RestPostById]
|
||||||
|
public ActionResult<CustomFilterResource> AddCustomFilter(CustomFilterResource resource)
|
||||||
|
{
|
||||||
|
var customFilter = _customFilterService.Add(resource.ToModel());
|
||||||
|
|
||||||
|
return Created(customFilter.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RestPutById]
|
||||||
|
public ActionResult<CustomFilterResource> UpdateCustomFilter(CustomFilterResource resource)
|
||||||
|
{
|
||||||
|
_customFilterService.Update(resource.ToModel());
|
||||||
|
return Accepted(resource.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RestDeleteById]
|
||||||
|
public void DeleteCustomResource(int id)
|
||||||
|
{
|
||||||
|
_customFilterService.Delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,49 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using Lidarr.Http;
|
|
||||||
using NzbDrone.Core.CustomFilters;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.CustomFilters
|
|
||||||
{
|
|
||||||
public class CustomFilterModule : LidarrRestModule<CustomFilterResource>
|
|
||||||
{
|
|
||||||
private readonly ICustomFilterService _customFilterService;
|
|
||||||
|
|
||||||
public CustomFilterModule(ICustomFilterService customFilterService)
|
|
||||||
{
|
|
||||||
_customFilterService = customFilterService;
|
|
||||||
|
|
||||||
GetResourceById = GetCustomFilter;
|
|
||||||
GetResourceAll = GetCustomFilters;
|
|
||||||
CreateResource = AddCustomFilter;
|
|
||||||
UpdateResource = UpdateCustomFilter;
|
|
||||||
DeleteResource = DeleteCustomResource;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CustomFilterResource GetCustomFilter(int id)
|
|
||||||
{
|
|
||||||
return _customFilterService.Get(id).ToResource();
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<CustomFilterResource> GetCustomFilters()
|
|
||||||
{
|
|
||||||
return _customFilterService.All().ToResource();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int AddCustomFilter(CustomFilterResource resource)
|
|
||||||
{
|
|
||||||
var customFilter = _customFilterService.Add(resource.ToModel());
|
|
||||||
|
|
||||||
return customFilter.Id;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateCustomFilter(CustomFilterResource resource)
|
|
||||||
{
|
|
||||||
_customFilterService.Update(resource.ToModel());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DeleteCustomResource(int id)
|
|
||||||
{
|
|
||||||
_customFilterService.Delete(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +1,21 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.DiskSpace;
|
using NzbDrone.Core.DiskSpace;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.DiskSpace
|
namespace Lidarr.Api.V1.DiskSpace
|
||||||
{
|
{
|
||||||
public class DiskSpaceModule : LidarrRestModule<DiskSpaceResource>
|
[V1ApiController("diskspace")]
|
||||||
|
public class DiskSpaceController : Controller
|
||||||
{
|
{
|
||||||
private readonly IDiskSpaceService _diskSpaceService;
|
private readonly IDiskSpaceService _diskSpaceService;
|
||||||
|
|
||||||
public DiskSpaceModule(IDiskSpaceService diskSpaceService)
|
public DiskSpaceController(IDiskSpaceService diskSpaceService)
|
||||||
: base("diskspace")
|
|
||||||
{
|
{
|
||||||
_diskSpaceService = diskSpaceService;
|
_diskSpaceService = diskSpaceService;
|
||||||
GetResourceAll = GetFreeSpace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
public List<DiskSpaceResource> GetFreeSpace()
|
public List<DiskSpaceResource> GetFreeSpace()
|
||||||
{
|
{
|
||||||
return _diskSpaceService.GetFreeSpace().ConvertAll(DiskSpaceResourceMapper.MapToResource);
|
return _diskSpaceService.GetFreeSpace().ConvertAll(DiskSpaceResourceMapper.MapToResource);
|
|
@ -1,12 +1,14 @@
|
||||||
using NzbDrone.Core.Download;
|
using Lidarr.Http;
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.DownloadClient
|
namespace Lidarr.Api.V1.DownloadClient
|
||||||
{
|
{
|
||||||
public class DownloadClientModule : ProviderModuleBase<DownloadClientResource, IDownloadClient, DownloadClientDefinition>
|
[V1ApiController]
|
||||||
|
public class DownloadClientController : ProviderControllerBase<DownloadClientResource, IDownloadClient, DownloadClientDefinition>
|
||||||
{
|
{
|
||||||
public static readonly DownloadClientResourceMapper ResourceMapper = new DownloadClientResourceMapper();
|
public static readonly DownloadClientResourceMapper ResourceMapper = new DownloadClientResourceMapper();
|
||||||
|
|
||||||
public DownloadClientModule(IDownloadClientFactory downloadClientFactory)
|
public DownloadClientController(IDownloadClientFactory downloadClientFactory)
|
||||||
: base(downloadClientFactory, "downloadclient", ResourceMapper)
|
: base(downloadClientFactory, "downloadclient", ResourceMapper)
|
||||||
{
|
{
|
||||||
}
|
}
|
|
@ -1,44 +1,36 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http.Extensions;
|
using Lidarr.Http;
|
||||||
using Nancy;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.FileSystem
|
namespace Lidarr.Api.V1.FileSystem
|
||||||
{
|
{
|
||||||
public class FileSystemModule : LidarrV1Module
|
[V1ApiController]
|
||||||
|
public class FileSystemController : Controller
|
||||||
{
|
{
|
||||||
private readonly IFileSystemLookupService _fileSystemLookupService;
|
private readonly IFileSystemLookupService _fileSystemLookupService;
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
private readonly IDiskScanService _diskScanService;
|
private readonly IDiskScanService _diskScanService;
|
||||||
|
|
||||||
public FileSystemModule(IFileSystemLookupService fileSystemLookupService,
|
public FileSystemController(IFileSystemLookupService fileSystemLookupService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IDiskScanService diskScanService)
|
IDiskScanService diskScanService)
|
||||||
: base("/filesystem")
|
|
||||||
{
|
{
|
||||||
_fileSystemLookupService = fileSystemLookupService;
|
_fileSystemLookupService = fileSystemLookupService;
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
_diskScanService = diskScanService;
|
_diskScanService = diskScanService;
|
||||||
Get("/", x => GetContents());
|
|
||||||
Get("/type", x => GetEntityType());
|
|
||||||
Get("/mediafiles", x => GetMediaFiles());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private object GetContents()
|
[HttpGet]
|
||||||
|
public IActionResult GetContents(string path, bool includeFiles = false, bool allowFoldersWithoutTrailingSlashes = false)
|
||||||
{
|
{
|
||||||
var pathQuery = Request.Query.path;
|
return Ok(_fileSystemLookupService.LookupContents(path, includeFiles, allowFoldersWithoutTrailingSlashes));
|
||||||
var includeFiles = Request.GetBooleanQueryParameter("includeFiles");
|
|
||||||
var allowFoldersWithoutTrailingSlashes = Request.GetBooleanQueryParameter("allowFoldersWithoutTrailingSlashes");
|
|
||||||
|
|
||||||
return _fileSystemLookupService.LookupContents((string)pathQuery.Value, includeFiles, allowFoldersWithoutTrailingSlashes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private object GetEntityType()
|
[HttpGet("type")]
|
||||||
|
public object GetEntityType(string path)
|
||||||
{
|
{
|
||||||
var pathQuery = Request.Query.path;
|
|
||||||
var path = (string)pathQuery.Value;
|
|
||||||
|
|
||||||
if (_diskProvider.FileExists(path))
|
if (_diskProvider.FileExists(path))
|
||||||
{
|
{
|
||||||
return new { type = "file" };
|
return new { type = "file" };
|
||||||
|
@ -48,11 +40,9 @@ namespace Lidarr.Api.V1.FileSystem
|
||||||
return new { type = "folder" };
|
return new { type = "folder" };
|
||||||
}
|
}
|
||||||
|
|
||||||
private object GetMediaFiles()
|
[HttpGet("mediafiles")]
|
||||||
|
public object GetMediaFiles(string path)
|
||||||
{
|
{
|
||||||
var pathQuery = Request.Query.path;
|
|
||||||
var path = (string)pathQuery.Value;
|
|
||||||
|
|
||||||
if (!_diskProvider.FolderExists(path))
|
if (!_diskProvider.FolderExists(path))
|
||||||
{
|
{
|
||||||
return new string[0];
|
return new string[0];
|
|
@ -1,5 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
using NzbDrone.Core.Datastore.Events;
|
||||||
using NzbDrone.Core.HealthCheck;
|
using NzbDrone.Core.HealthCheck;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
@ -7,23 +10,30 @@ using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Health
|
namespace Lidarr.Api.V1.Health
|
||||||
{
|
{
|
||||||
public class HealthModule : LidarrRestModuleWithSignalR<HealthResource, HealthCheck>,
|
[V1ApiController]
|
||||||
|
public class HealthController : RestControllerWithSignalR<HealthResource, HealthCheck>,
|
||||||
IHandle<HealthCheckCompleteEvent>
|
IHandle<HealthCheckCompleteEvent>
|
||||||
{
|
{
|
||||||
private readonly IHealthCheckService _healthCheckService;
|
private readonly IHealthCheckService _healthCheckService;
|
||||||
|
|
||||||
public HealthModule(IBroadcastSignalRMessage signalRBroadcaster, IHealthCheckService healthCheckService)
|
public HealthController(IBroadcastSignalRMessage signalRBroadcaster, IHealthCheckService healthCheckService)
|
||||||
: base(signalRBroadcaster)
|
: base(signalRBroadcaster)
|
||||||
{
|
{
|
||||||
_healthCheckService = healthCheckService;
|
_healthCheckService = healthCheckService;
|
||||||
GetResourceAll = GetHealth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<HealthResource> GetHealth()
|
public override HealthResource GetResourceById(int id)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public List<HealthResource> GetHealth()
|
||||||
{
|
{
|
||||||
return _healthCheckService.Results().ToResource();
|
return _healthCheckService.Results().ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(HealthCheckCompleteEvent message)
|
public void Handle(HealthCheckCompleteEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Sync);
|
BroadcastResourceChange(ModelAction.Sync);
|
|
@ -6,8 +6,7 @@ using Lidarr.Api.V1.Artist;
|
||||||
using Lidarr.Api.V1.Tracks;
|
using Lidarr.Api.V1.Tracks;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.Extensions;
|
using Lidarr.Http.Extensions;
|
||||||
using Lidarr.Http.REST;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Nancy;
|
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||||
using NzbDrone.Core.Download;
|
using NzbDrone.Core.Download;
|
||||||
|
@ -15,24 +14,20 @@ using NzbDrone.Core.History;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.History
|
namespace Lidarr.Api.V1.History
|
||||||
{
|
{
|
||||||
public class HistoryModule : LidarrRestModule<HistoryResource>
|
[V1ApiController]
|
||||||
|
public class HistoryController : Controller
|
||||||
{
|
{
|
||||||
private readonly IHistoryService _historyService;
|
private readonly IHistoryService _historyService;
|
||||||
private readonly IUpgradableSpecification _upgradableSpecification;
|
private readonly IUpgradableSpecification _upgradableSpecification;
|
||||||
private readonly IFailedDownloadService _failedDownloadService;
|
private readonly IFailedDownloadService _failedDownloadService;
|
||||||
|
|
||||||
public HistoryModule(IHistoryService historyService,
|
public HistoryController(IHistoryService historyService,
|
||||||
IUpgradableSpecification upgradableSpecification,
|
IUpgradableSpecification upgradableSpecification,
|
||||||
IFailedDownloadService failedDownloadService)
|
IFailedDownloadService failedDownloadService)
|
||||||
{
|
{
|
||||||
_historyService = historyService;
|
_historyService = historyService;
|
||||||
_upgradableSpecification = upgradableSpecification;
|
_upgradableSpecification = upgradableSpecification;
|
||||||
_failedDownloadService = failedDownloadService;
|
_failedDownloadService = failedDownloadService;
|
||||||
GetResourcePaged = GetHistory;
|
|
||||||
|
|
||||||
Get("/since", x => GetHistorySince());
|
|
||||||
Get("/artist", x => GetArtistHistory());
|
|
||||||
Post("/failed", x => MarkAsFailed());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HistoryResource MapToResource(NzbDrone.Core.History.History model, bool includeArtist, bool includeAlbum, bool includeTrack)
|
protected HistoryResource MapToResource(NzbDrone.Core.History.History model, bool includeArtist, bool includeAlbum, bool includeTrack)
|
||||||
|
@ -62,12 +57,11 @@ namespace Lidarr.Api.V1.History
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PagingResource<HistoryResource> GetHistory(PagingResource<HistoryResource> pagingResource)
|
[HttpGet]
|
||||||
|
public PagingResource<HistoryResource> GetHistory(bool includeArtist = false, bool includeAlbum = false, bool includeTrack = false)
|
||||||
{
|
{
|
||||||
|
var pagingResource = Request.ReadPagingResourceFromRequest<HistoryResource>();
|
||||||
var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, NzbDrone.Core.History.History>("date", SortDirection.Descending);
|
var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, NzbDrone.Core.History.History>("date", SortDirection.Descending);
|
||||||
var includeArtist = Request.GetBooleanQueryParameter("includeArtist");
|
|
||||||
var includeAlbum = Request.GetBooleanQueryParameter("includeAlbum");
|
|
||||||
var includeTrack = Request.GetBooleanQueryParameter("includeTrack");
|
|
||||||
|
|
||||||
var eventTypeFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "eventType");
|
var eventTypeFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "eventType");
|
||||||
var albumIdFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "albumId");
|
var albumIdFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "albumId");
|
||||||
|
@ -91,68 +85,29 @@ namespace Lidarr.Api.V1.History
|
||||||
pagingSpec.FilterExpressions.Add(h => h.DownloadId == downloadId);
|
pagingSpec.FilterExpressions.Add(h => h.DownloadId == downloadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ApplyToPage(_historyService.Paged, pagingSpec, h => MapToResource(h, includeArtist, includeAlbum, includeTrack));
|
return pagingSpec.ApplyToPage(_historyService.Paged, h => MapToResource(h, includeArtist, includeAlbum, includeTrack));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<HistoryResource> GetHistorySince()
|
[HttpGet("since")]
|
||||||
|
public List<HistoryResource> GetHistorySince(DateTime date, HistoryEventType? eventType = null, bool includeArtist = false, bool includeAlbum = false, bool includeTrack = false)
|
||||||
{
|
{
|
||||||
var queryDate = Request.Query.Date;
|
|
||||||
var queryEventType = Request.Query.EventType;
|
|
||||||
|
|
||||||
if (!queryDate.HasValue)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("date is missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
DateTime date = DateTime.Parse(queryDate.Value);
|
|
||||||
HistoryEventType? eventType = null;
|
|
||||||
var includeArtist = Request.GetBooleanQueryParameter("includeArtist");
|
|
||||||
var includeAlbum = Request.GetBooleanQueryParameter("includeAlbum");
|
|
||||||
var includeTrack = Request.GetBooleanQueryParameter("includeTrack");
|
|
||||||
|
|
||||||
if (queryEventType.HasValue)
|
|
||||||
{
|
|
||||||
eventType = (HistoryEventType)Convert.ToInt32(queryEventType.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _historyService.Since(date, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum, includeTrack)).ToList();
|
return _historyService.Since(date, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum, includeTrack)).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<HistoryResource> GetArtistHistory()
|
[HttpGet("artist")]
|
||||||
|
public List<HistoryResource> GetArtistHistory(int artistId, int? albumId = null, HistoryEventType? eventType = null, bool includeArtist = false, bool includeAlbum = false, bool includeTrack = false)
|
||||||
{
|
{
|
||||||
var queryArtistId = Request.Query.ArtistId;
|
if (albumId.HasValue)
|
||||||
var queryAlbumId = Request.Query.AlbumId;
|
|
||||||
var queryEventType = Request.Query.EventType;
|
|
||||||
|
|
||||||
if (!queryArtistId.HasValue)
|
|
||||||
{
|
{
|
||||||
throw new BadRequestException("artistId is missing");
|
return _historyService.GetByAlbum(albumId.Value, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum, includeTrack)).ToList();
|
||||||
}
|
|
||||||
|
|
||||||
int artistId = Convert.ToInt32(queryArtistId.Value);
|
|
||||||
HistoryEventType? eventType = null;
|
|
||||||
var includeArtist = Request.GetBooleanQueryParameter("includeArtist");
|
|
||||||
var includeAlbum = Request.GetBooleanQueryParameter("includeAlbum");
|
|
||||||
var includeTrack = Request.GetBooleanQueryParameter("includeTrack");
|
|
||||||
|
|
||||||
if (queryEventType.HasValue)
|
|
||||||
{
|
|
||||||
eventType = (HistoryEventType)Convert.ToInt32(queryEventType.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queryAlbumId.HasValue)
|
|
||||||
{
|
|
||||||
int albumId = Convert.ToInt32(queryAlbumId.Value);
|
|
||||||
|
|
||||||
return _historyService.GetByAlbum(albumId, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum, includeTrack)).ToList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return _historyService.GetByArtist(artistId, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum, includeTrack)).ToList();
|
return _historyService.GetByArtist(artistId, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum, includeTrack)).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private object MarkAsFailed()
|
[HttpPost("failed")]
|
||||||
|
public object MarkAsFailed([FromBody] int id)
|
||||||
{
|
{
|
||||||
var id = (int)Request.Form.Id;
|
|
||||||
_failedDownloadService.MarkAsFailed(id);
|
_failedDownloadService.MarkAsFailed(id);
|
||||||
return new object();
|
return new object();
|
||||||
}
|
}
|
|
@ -1,14 +1,16 @@
|
||||||
|
using Lidarr.Http;
|
||||||
using NzbDrone.Core.ImportLists;
|
using NzbDrone.Core.ImportLists;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
using NzbDrone.Core.Validation.Paths;
|
using NzbDrone.Core.Validation.Paths;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.ImportLists
|
namespace Lidarr.Api.V1.ImportLists
|
||||||
{
|
{
|
||||||
public class ImportListModule : ProviderModuleBase<ImportListResource, IImportList, ImportListDefinition>
|
[V1ApiController]
|
||||||
|
public class ImportListController : ProviderControllerBase<ImportListResource, IImportList, ImportListDefinition>
|
||||||
{
|
{
|
||||||
public static readonly ImportListResourceMapper ResourceMapper = new ImportListResourceMapper();
|
public static readonly ImportListResourceMapper ResourceMapper = new ImportListResourceMapper();
|
||||||
|
|
||||||
public ImportListModule(ImportListFactory importListFactory,
|
public ImportListController(ImportListFactory importListFactory,
|
||||||
QualityProfileExistsValidator qualityProfileExistsValidator,
|
QualityProfileExistsValidator qualityProfileExistsValidator,
|
||||||
MetadataProfileExistsValidator metadataProfileExistsValidator)
|
MetadataProfileExistsValidator metadataProfileExistsValidator)
|
||||||
: base(importListFactory, "importlist", ResourceMapper)
|
: base(importListFactory, "importlist", ResourceMapper)
|
|
@ -1,54 +1,57 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.ImportLists.Exclusions;
|
using NzbDrone.Core.ImportLists.Exclusions;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.ImportLists
|
namespace Lidarr.Api.V1.ImportLists
|
||||||
{
|
{
|
||||||
public class ImportListExclusionModule : LidarrRestModule<ImportListExclusionResource>
|
[V1ApiController]
|
||||||
|
public class ImportListExclusionController : RestController<ImportListExclusionResource>
|
||||||
{
|
{
|
||||||
private readonly IImportListExclusionService _importListExclusionService;
|
private readonly IImportListExclusionService _importListExclusionService;
|
||||||
|
|
||||||
public ImportListExclusionModule(IImportListExclusionService importListExclusionService,
|
public ImportListExclusionController(IImportListExclusionService importListExclusionService,
|
||||||
ImportListExclusionExistsValidator importListExclusionExistsValidator,
|
ImportListExclusionExistsValidator importListExclusionExistsValidator,
|
||||||
GuidValidator guidValidator)
|
GuidValidator guidValidator)
|
||||||
{
|
{
|
||||||
_importListExclusionService = importListExclusionService;
|
_importListExclusionService = importListExclusionService;
|
||||||
|
|
||||||
GetResourceById = GetImportListExclusion;
|
|
||||||
GetResourceAll = GetImportListExclusions;
|
|
||||||
CreateResource = AddImportListExclusion;
|
|
||||||
UpdateResource = UpdateImportListExclusion;
|
|
||||||
DeleteResource = DeleteImportListExclusionResource;
|
|
||||||
|
|
||||||
SharedValidator.RuleFor(c => c.ForeignId).NotEmpty().SetValidator(guidValidator).SetValidator(importListExclusionExistsValidator);
|
SharedValidator.RuleFor(c => c.ForeignId).NotEmpty().SetValidator(guidValidator).SetValidator(importListExclusionExistsValidator);
|
||||||
SharedValidator.RuleFor(c => c.ArtistName).NotEmpty();
|
SharedValidator.RuleFor(c => c.ArtistName).NotEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImportListExclusionResource GetImportListExclusion(int id)
|
public override ImportListExclusionResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
return _importListExclusionService.Get(id).ToResource();
|
return _importListExclusionService.Get(id).ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ImportListExclusionResource> GetImportListExclusions()
|
[HttpGet]
|
||||||
|
public List<ImportListExclusionResource> GetImportListExclusions()
|
||||||
{
|
{
|
||||||
return _importListExclusionService.All().ToResource();
|
return _importListExclusionService.All().ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int AddImportListExclusion(ImportListExclusionResource resource)
|
[RestPostById]
|
||||||
|
public ActionResult<ImportListExclusionResource> AddImportListExclusion(ImportListExclusionResource resource)
|
||||||
{
|
{
|
||||||
var customFilter = _importListExclusionService.Add(resource.ToModel());
|
var customFilter = _importListExclusionService.Add(resource.ToModel());
|
||||||
|
|
||||||
return customFilter.Id;
|
return Created(customFilter.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateImportListExclusion(ImportListExclusionResource resource)
|
[RestPutById]
|
||||||
|
public ActionResult<ImportListExclusionResource> UpdateImportListExclusion(ImportListExclusionResource resource)
|
||||||
{
|
{
|
||||||
_importListExclusionService.Update(resource.ToModel());
|
_importListExclusionService.Update(resource.ToModel());
|
||||||
|
return Accepted(resource.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteImportListExclusionResource(int id)
|
[RestDeleteById]
|
||||||
|
public void DeleteImportListExclusionResource(int id)
|
||||||
{
|
{
|
||||||
_importListExclusionService.Delete(id);
|
_importListExclusionService.Delete(id);
|
||||||
}
|
}
|
|
@ -1,12 +1,14 @@
|
||||||
using NzbDrone.Core.Indexers;
|
using Lidarr.Http;
|
||||||
|
using NzbDrone.Core.Indexers;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Indexers
|
namespace Lidarr.Api.V1.Indexers
|
||||||
{
|
{
|
||||||
public class IndexerModule : ProviderModuleBase<IndexerResource, IIndexer, IndexerDefinition>
|
[V1ApiController]
|
||||||
|
public class IndexerController : ProviderControllerBase<IndexerResource, IIndexer, IndexerDefinition>
|
||||||
{
|
{
|
||||||
public static readonly IndexerResourceMapper ResourceMapper = new IndexerResourceMapper();
|
public static readonly IndexerResourceMapper ResourceMapper = new IndexerResourceMapper();
|
||||||
|
|
||||||
public IndexerModule(IndexerFactory indexerFactory)
|
public IndexerController(IndexerFactory indexerFactory)
|
||||||
: base(indexerFactory, "indexer", ResourceMapper)
|
: base(indexerFactory, "indexer", ResourceMapper)
|
||||||
{
|
{
|
||||||
}
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Nancy;
|
using Lidarr.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Cache;
|
using NzbDrone.Common.Cache;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
@ -18,7 +19,8 @@ using HttpStatusCode = System.Net.HttpStatusCode;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Indexers
|
namespace Lidarr.Api.V1.Indexers
|
||||||
{
|
{
|
||||||
public class ReleaseModule : ReleaseModuleBase
|
[V1ApiController]
|
||||||
|
public class ReleaseController : ReleaseControllerBase
|
||||||
{
|
{
|
||||||
private readonly IAlbumService _albumService;
|
private readonly IAlbumService _albumService;
|
||||||
private readonly IArtistService _artistService;
|
private readonly IArtistService _artistService;
|
||||||
|
@ -32,7 +34,7 @@ namespace Lidarr.Api.V1.Indexers
|
||||||
|
|
||||||
private readonly ICached<RemoteAlbum> _remoteAlbumCache;
|
private readonly ICached<RemoteAlbum> _remoteAlbumCache;
|
||||||
|
|
||||||
public ReleaseModule(IAlbumService albumService,
|
public ReleaseController(IAlbumService albumService,
|
||||||
IArtistService artistService,
|
IArtistService artistService,
|
||||||
IFetchAndParseRss rssFetcherAndParser,
|
IFetchAndParseRss rssFetcherAndParser,
|
||||||
ISearchForNzb nzbSearchService,
|
ISearchForNzb nzbSearchService,
|
||||||
|
@ -53,17 +55,17 @@ namespace Lidarr.Api.V1.Indexers
|
||||||
_downloadService = downloadService;
|
_downloadService = downloadService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
GetResourceAll = GetReleases;
|
|
||||||
Post("/", x => DownloadRelease(ReadResourceFromRequest()));
|
|
||||||
|
|
||||||
PostValidator.RuleFor(s => s.IndexerId).ValidId();
|
PostValidator.RuleFor(s => s.IndexerId).ValidId();
|
||||||
PostValidator.RuleFor(s => s.Guid).NotEmpty();
|
PostValidator.RuleFor(s => s.Guid).NotEmpty();
|
||||||
|
|
||||||
_remoteAlbumCache = cacheManager.GetCache<RemoteAlbum>(GetType(), "remoteAlbums");
|
_remoteAlbumCache = cacheManager.GetCache<RemoteAlbum>(GetType(), "remoteAlbums");
|
||||||
}
|
}
|
||||||
|
|
||||||
private object DownloadRelease(ReleaseResource release)
|
[HttpPost]
|
||||||
|
public ActionResult<ReleaseResource> Create(ReleaseResource release)
|
||||||
{
|
{
|
||||||
|
ValidateResource(release);
|
||||||
|
|
||||||
var remoteAlbum = _remoteAlbumCache.Find(GetCacheKey(release));
|
var remoteAlbum = _remoteAlbumCache.Find(GetCacheKey(release));
|
||||||
|
|
||||||
if (remoteAlbum == null)
|
if (remoteAlbum == null)
|
||||||
|
@ -129,19 +131,20 @@ namespace Lidarr.Api.V1.Indexers
|
||||||
throw new NzbDroneClientException(HttpStatusCode.Conflict, "Getting release from indexer failed");
|
throw new NzbDroneClientException(HttpStatusCode.Conflict, "Getting release from indexer failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
return release;
|
return Ok(release);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ReleaseResource> GetReleases()
|
[HttpGet]
|
||||||
|
public List<ReleaseResource> GetReleases(int? albumId, int? artistId)
|
||||||
{
|
{
|
||||||
if (Request.Query.albumId.HasValue)
|
if (albumId.HasValue)
|
||||||
{
|
{
|
||||||
return GetAlbumReleases(Request.Query.albumId);
|
return GetAlbumReleases(int.Parse(Request.Query["albumId"]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Request.Query.artistId.HasValue)
|
if (artistId.HasValue)
|
||||||
{
|
{
|
||||||
return GetArtistReleases(Request.Query.artistId);
|
return GetArtistReleases(int.Parse(Request.Query["artistId"]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetRss();
|
return GetRss();
|
|
@ -1,11 +1,17 @@
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http.REST;
|
||||||
using NzbDrone.Core.DecisionEngine;
|
using NzbDrone.Core.DecisionEngine;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Indexers
|
namespace Lidarr.Api.V1.Indexers
|
||||||
{
|
{
|
||||||
public abstract class ReleaseModuleBase : LidarrRestModule<ReleaseResource>
|
public abstract class ReleaseControllerBase : RestController<ReleaseResource>
|
||||||
{
|
{
|
||||||
|
public override ReleaseResource GetResourceById(int id)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual List<ReleaseResource> MapDecisions(IEnumerable<DownloadDecision> decisions)
|
protected virtual List<ReleaseResource> MapDecisions(IEnumerable<DownloadDecision> decisions)
|
||||||
{
|
{
|
||||||
var result = new List<ReleaseResource>();
|
var result = new List<ReleaseResource>();
|
|
@ -2,6 +2,8 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using FluentValidation.Results;
|
using FluentValidation.Results;
|
||||||
|
using Lidarr.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
|
@ -12,14 +14,15 @@ using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Indexers
|
namespace Lidarr.Api.V1.Indexers
|
||||||
{
|
{
|
||||||
internal class ReleasePushModule : ReleaseModuleBase
|
[V1ApiController("release/push")]
|
||||||
|
public class ReleasePushController : ReleaseControllerBase
|
||||||
{
|
{
|
||||||
private readonly IMakeDownloadDecision _downloadDecisionMaker;
|
private readonly IMakeDownloadDecision _downloadDecisionMaker;
|
||||||
private readonly IProcessDownloadDecisions _downloadDecisionProcessor;
|
private readonly IProcessDownloadDecisions _downloadDecisionProcessor;
|
||||||
private readonly IIndexerFactory _indexerFactory;
|
private readonly IIndexerFactory _indexerFactory;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public ReleasePushModule(IMakeDownloadDecision downloadDecisionMaker,
|
public ReleasePushController(IMakeDownloadDecision downloadDecisionMaker,
|
||||||
IProcessDownloadDecisions downloadDecisionProcessor,
|
IProcessDownloadDecisions downloadDecisionProcessor,
|
||||||
IIndexerFactory indexerFactory,
|
IIndexerFactory indexerFactory,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
|
@ -29,18 +32,19 @@ namespace Lidarr.Api.V1.Indexers
|
||||||
_indexerFactory = indexerFactory;
|
_indexerFactory = indexerFactory;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
Post("/push", x => ProcessRelease(ReadResourceFromRequest()));
|
|
||||||
|
|
||||||
PostValidator.RuleFor(s => s.Title).NotEmpty();
|
PostValidator.RuleFor(s => s.Title).NotEmpty();
|
||||||
PostValidator.RuleFor(s => s.DownloadUrl).NotEmpty();
|
PostValidator.RuleFor(s => s.DownloadUrl).NotEmpty();
|
||||||
PostValidator.RuleFor(s => s.Protocol).NotEmpty();
|
PostValidator.RuleFor(s => s.Protocol).NotEmpty();
|
||||||
PostValidator.RuleFor(s => s.PublishDate).NotEmpty();
|
PostValidator.RuleFor(s => s.PublishDate).NotEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private object ProcessRelease(ReleaseResource release)
|
[HttpPost]
|
||||||
|
public ActionResult<ReleaseResource> Create(ReleaseResource release)
|
||||||
{
|
{
|
||||||
_logger.Info("Release pushed: {0} - {1}", release.Title, release.DownloadUrl);
|
_logger.Info("Release pushed: {0} - {1}", release.Title, release.DownloadUrl);
|
||||||
|
|
||||||
|
ValidateResource(release);
|
||||||
|
|
||||||
var info = release.ToModel();
|
var info = release.ToModel();
|
||||||
|
|
||||||
info.Guid = "PUSH-" + info.DownloadUrl;
|
info.Guid = "PUSH-" + info.DownloadUrl;
|
|
@ -9,11 +9,9 @@
|
||||||
<ProjectReference Include="..\NzbDrone.SignalR\Lidarr.SignalR.csproj" />
|
<ProjectReference Include="..\NzbDrone.SignalR\Lidarr.SignalR.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" />
|
||||||
<PackageReference Include="FluentValidation" Version="8.6.2" />
|
<PackageReference Include="FluentValidation" Version="8.6.2" />
|
||||||
<PackageReference Include="Ical.Net" Version="4.2.0" />
|
<PackageReference Include="Ical.Net" Version="4.2.0" />
|
||||||
<PackageReference Include="Nancy" Version="2.0.0" />
|
|
||||||
<PackageReference Include="Nancy.Authentication.Basic" Version="2.0.0" />
|
|
||||||
<PackageReference Include="Nancy.Authentication.Forms" Version="2.0.0" />
|
|
||||||
<PackageReference Include="NLog" Version="4.7.9" />
|
<PackageReference Include="NLog" Version="4.7.9" />
|
||||||
<PackageReference Include="System.IO.Abstractions" Version="13.2.29" />
|
<PackageReference Include="System.IO.Abstractions" Version="13.2.29" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
using Lidarr.Http;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1
|
|
||||||
{
|
|
||||||
public abstract class LidarrV1FeedModule : LidarrModule
|
|
||||||
{
|
|
||||||
protected LidarrV1FeedModule(string resource)
|
|
||||||
: base("/feed/v1/" + resource.Trim('/'))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
using Lidarr.Http;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1
|
|
||||||
{
|
|
||||||
public abstract class LidarrV1Module : LidarrModule
|
|
||||||
{
|
|
||||||
protected LidarrV1Module(string resource)
|
|
||||||
: base("/api/v1/" + resource.Trim('/'))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +1,25 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.Extensions;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Instrumentation;
|
using NzbDrone.Core.Instrumentation;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Logs
|
namespace Lidarr.Api.V1.Logs
|
||||||
{
|
{
|
||||||
public class LogModule : LidarrRestModule<LogResource>
|
[V1ApiController]
|
||||||
|
public class LogController : Controller
|
||||||
{
|
{
|
||||||
private readonly ILogService _logService;
|
private readonly ILogService _logService;
|
||||||
|
|
||||||
public LogModule(ILogService logService)
|
public LogController(ILogService logService)
|
||||||
{
|
{
|
||||||
_logService = logService;
|
_logService = logService;
|
||||||
GetResourcePaged = GetLogs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PagingResource<LogResource> GetLogs(PagingResource<LogResource> pagingResource)
|
[HttpGet]
|
||||||
|
public PagingResource<LogResource> GetLogs()
|
||||||
{
|
{
|
||||||
|
var pagingResource = Request.ReadPagingResourceFromRequest<LogResource>();
|
||||||
var pageSpec = pagingResource.MapToPagingSpec<LogResource, Log>();
|
var pageSpec = pagingResource.MapToPagingSpec<LogResource, Log>();
|
||||||
|
|
||||||
if (pageSpec.SortKey == "time")
|
if (pageSpec.SortKey == "time")
|
||||||
|
@ -50,7 +54,7 @@ namespace Lidarr.Api.V1.Logs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = ApplyToPage(_logService.Paged, pageSpec, LogResourceMapper.ToResource);
|
var response = pageSpec.ApplyToPage(_logService.Paged, LogResourceMapper.ToResource);
|
||||||
|
|
||||||
if (pageSpec.SortKey == "id")
|
if (pageSpec.SortKey == "id")
|
||||||
{
|
{
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using Lidarr.Http;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
@ -7,12 +8,13 @@ using NzbDrone.Core.Configuration;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Logs
|
namespace Lidarr.Api.V1.Logs
|
||||||
{
|
{
|
||||||
public class LogFileModule : LogFileModuleBase
|
[V1ApiController("log/file")]
|
||||||
|
public class LogFileController : LogFileControllerBase
|
||||||
{
|
{
|
||||||
private readonly IAppFolderInfo _appFolderInfo;
|
private readonly IAppFolderInfo _appFolderInfo;
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
|
|
||||||
public LogFileModule(IAppFolderInfo appFolderInfo,
|
public LogFileController(IAppFolderInfo appFolderInfo,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IConfigFileProvider configFileProvider)
|
IConfigFileProvider configFileProvider)
|
||||||
: base(diskProvider, configFileProvider, "")
|
: base(diskProvider, configFileProvider, "")
|
|
@ -1,35 +1,32 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Nancy;
|
|
||||||
using Nancy.Responses;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Logs
|
namespace Lidarr.Api.V1.Logs
|
||||||
{
|
{
|
||||||
public abstract class LogFileModuleBase : LidarrRestModule<LogFileResource>
|
public abstract class LogFileControllerBase : Controller
|
||||||
{
|
{
|
||||||
protected const string LOGFILE_ROUTE = @"/(?<filename>[-.a-zA-Z0-9]+?\.txt)";
|
protected const string LOGFILE_ROUTE = @"/(?<filename>[-.a-zA-Z0-9]+?\.txt)";
|
||||||
|
protected string _resource;
|
||||||
|
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
private readonly IConfigFileProvider _configFileProvider;
|
private readonly IConfigFileProvider _configFileProvider;
|
||||||
|
|
||||||
public LogFileModuleBase(IDiskProvider diskProvider,
|
public LogFileControllerBase(IDiskProvider diskProvider,
|
||||||
IConfigFileProvider configFileProvider,
|
IConfigFileProvider configFileProvider,
|
||||||
string route)
|
string resource)
|
||||||
: base("log/file" + route)
|
|
||||||
{
|
{
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
_configFileProvider = configFileProvider;
|
_configFileProvider = configFileProvider;
|
||||||
GetResourceAll = GetLogFilesResponse;
|
_resource = resource;
|
||||||
|
|
||||||
Get(LOGFILE_ROUTE, options => GetLogFileResponse(options.filename));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<LogFileResource> GetLogFilesResponse()
|
[HttpGet]
|
||||||
|
public List<LogFileResource> GetLogFilesResponse()
|
||||||
{
|
{
|
||||||
var result = new List<LogFileResource>();
|
var result = new List<LogFileResource>();
|
||||||
|
|
||||||
|
@ -45,7 +42,7 @@ namespace Lidarr.Api.V1.Logs
|
||||||
Id = i + 1,
|
Id = i + 1,
|
||||||
Filename = filename,
|
Filename = filename,
|
||||||
LastWriteTime = _diskProvider.FileGetLastWrite(file),
|
LastWriteTime = _diskProvider.FileGetLastWrite(file),
|
||||||
ContentsUrl = string.Format("{0}/api/v1/{1}/{2}", _configFileProvider.UrlBase, Resource, filename),
|
ContentsUrl = string.Format("{0}/api/v1/{1}/{2}", _configFileProvider.UrlBase, _resource, filename),
|
||||||
DownloadUrl = string.Format("{0}/{1}/{2}", _configFileProvider.UrlBase, DownloadUrlRoot, filename)
|
DownloadUrl = string.Format("{0}/{1}/{2}", _configFileProvider.UrlBase, DownloadUrlRoot, filename)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -53,7 +50,8 @@ namespace Lidarr.Api.V1.Logs
|
||||||
return result.OrderByDescending(l => l.LastWriteTime).ToList();
|
return result.OrderByDescending(l => l.LastWriteTime).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private object GetLogFileResponse(string filename)
|
[HttpGet(@"{filename:regex([[-.a-zA-Z0-9]]+?\.txt)}")]
|
||||||
|
public IActionResult GetLogFileResponse(string filename)
|
||||||
{
|
{
|
||||||
LogManager.Flush();
|
LogManager.Flush();
|
||||||
|
|
||||||
|
@ -61,12 +59,10 @@ namespace Lidarr.Api.V1.Logs
|
||||||
|
|
||||||
if (!_diskProvider.FileExists(filePath))
|
if (!_diskProvider.FileExists(filePath))
|
||||||
{
|
{
|
||||||
return new NotFoundResponse();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = _diskProvider.ReadAllText(filePath);
|
return PhysicalFile(filePath, "text/plain");
|
||||||
|
|
||||||
return new TextResponse(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract IEnumerable<string> GetLogFiles();
|
protected abstract IEnumerable<string> GetLogFiles();
|
|
@ -1,7 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using Lidarr.Http;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
@ -9,15 +10,16 @@ using NzbDrone.Core.Configuration;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Logs
|
namespace Lidarr.Api.V1.Logs
|
||||||
{
|
{
|
||||||
public class UpdateLogFileModule : LogFileModuleBase
|
[V1ApiController("log/file/update")]
|
||||||
|
public class UpdateLogFileController : LogFileControllerBase
|
||||||
{
|
{
|
||||||
private readonly IAppFolderInfo _appFolderInfo;
|
private readonly IAppFolderInfo _appFolderInfo;
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
|
|
||||||
public UpdateLogFileModule(IAppFolderInfo appFolderInfo,
|
public UpdateLogFileController(IAppFolderInfo appFolderInfo,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IConfigFileProvider configFileProvider)
|
IConfigFileProvider configFileProvider)
|
||||||
: base(diskProvider, configFileProvider, "/update")
|
: base(diskProvider, configFileProvider, "update")
|
||||||
{
|
{
|
||||||
_appFolderInfo = appFolderInfo;
|
_appFolderInfo = appFolderInfo;
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
|
@ -1,9 +1,7 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.Extensions;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Nancy;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
using NzbDrone.Core.MediaFiles.TrackImport.Manual;
|
using NzbDrone.Core.MediaFiles.TrackImport.Manual;
|
||||||
|
@ -12,7 +10,8 @@ using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.ManualImport
|
namespace Lidarr.Api.V1.ManualImport
|
||||||
{
|
{
|
||||||
public class ManualImportModule : LidarrRestModule<ManualImportResource>
|
[V1ApiController]
|
||||||
|
public class ManualImportController : Controller
|
||||||
{
|
{
|
||||||
private readonly IArtistService _artistService;
|
private readonly IArtistService _artistService;
|
||||||
private readonly IAlbumService _albumService;
|
private readonly IAlbumService _albumService;
|
||||||
|
@ -20,7 +19,7 @@ namespace Lidarr.Api.V1.ManualImport
|
||||||
private readonly IManualImportService _manualImportService;
|
private readonly IManualImportService _manualImportService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public ManualImportModule(IManualImportService manualImportService,
|
public ManualImportController(IManualImportService manualImportService,
|
||||||
IArtistService artistService,
|
IArtistService artistService,
|
||||||
IAlbumService albumService,
|
IAlbumService albumService,
|
||||||
IReleaseService releaseService,
|
IReleaseService releaseService,
|
||||||
|
@ -31,31 +30,25 @@ namespace Lidarr.Api.V1.ManualImport
|
||||||
_releaseService = releaseService;
|
_releaseService = releaseService;
|
||||||
_manualImportService = manualImportService;
|
_manualImportService = manualImportService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
GetResourceAll = GetMediaFiles;
|
|
||||||
|
|
||||||
Put("/", options =>
|
|
||||||
{
|
|
||||||
var resource = Request.Body.FromJson<List<ManualImportResource>>();
|
|
||||||
return ResponseWithCode(UpdateImportItems(resource), HttpStatusCode.Accepted);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ManualImportResource> GetMediaFiles()
|
[HttpPut]
|
||||||
|
public IActionResult UpdateItems(List<ManualImportResource> resource)
|
||||||
|
{
|
||||||
|
return Accepted(UpdateImportItems(resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public List<ManualImportResource> GetMediaFiles(string folder, string downloadId, int? artistId, bool filterExistingFiles = true, bool replaceExistingFiles = true)
|
||||||
{
|
{
|
||||||
var folder = (string)Request.Query.folder;
|
|
||||||
var downloadId = (string)Request.Query.downloadId;
|
|
||||||
NzbDrone.Core.Music.Artist artist = null;
|
NzbDrone.Core.Music.Artist artist = null;
|
||||||
|
|
||||||
var artistIdQuery = Request.GetNullableIntegerQueryParameter("artistId", null);
|
if (artistId > 0)
|
||||||
|
|
||||||
if (artistIdQuery.HasValue && artistIdQuery.Value > 0)
|
|
||||||
{
|
{
|
||||||
artist = _artistService.GetArtist(Convert.ToInt32(artistIdQuery.Value));
|
artist = _artistService.GetArtist(artistId.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
var filter = Request.GetBooleanQueryParameter("filterExistingFiles", true) ? FilterFilesType.Matched : FilterFilesType.None;
|
var filter = filterExistingFiles ? FilterFilesType.Matched : FilterFilesType.None;
|
||||||
var replaceExistingFiles = Request.GetBooleanQueryParameter("replaceExistingFiles", true);
|
|
||||||
|
|
||||||
return _manualImportService.GetMediaFiles(folder, downloadId, artist, filter, replaceExistingFiles).ToResource().Select(AddQualityWeight).ToList();
|
return _manualImportService.GetMediaFiles(folder, downloadId, artist, filter, replaceExistingFiles).ToResource().Select(AddQualityWeight).ToList();
|
||||||
}
|
}
|
|
@ -1,34 +1,32 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Nancy;
|
using Lidarr.Http;
|
||||||
using Nancy.Responses;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.StaticFiles;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.MediaCovers
|
namespace Lidarr.Api.V1.MediaCovers
|
||||||
{
|
{
|
||||||
public class MediaCoverModule : LidarrV1Module
|
[V1ApiController]
|
||||||
|
public class MediaCoverController : Controller
|
||||||
{
|
{
|
||||||
private const string MEDIA_COVER_ARTIST_ROUTE = @"/Artist/(?<artistId>\d+)/(?<filename>(.+)\.(jpg|png|gif))";
|
|
||||||
private const string MEDIA_COVER_ALBUM_ROUTE = @"/Album/(?<artistId>\d+)/(?<filename>(.+)\.(jpg|png|gif))";
|
|
||||||
|
|
||||||
private static readonly Regex RegexResizedImage = new Regex(@"-\d+(?=\.(jpg|png|gif)$)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
private static readonly Regex RegexResizedImage = new Regex(@"-\d+(?=\.(jpg|png|gif)$)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
private readonly IAppFolderInfo _appFolderInfo;
|
private readonly IAppFolderInfo _appFolderInfo;
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
|
private readonly IContentTypeProvider _mimeTypeProvider;
|
||||||
|
|
||||||
public MediaCoverModule(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider)
|
public MediaCoverController(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider)
|
||||||
: base("MediaCover")
|
|
||||||
{
|
{
|
||||||
_appFolderInfo = appFolderInfo;
|
_appFolderInfo = appFolderInfo;
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
|
_mimeTypeProvider = new FileExtensionContentTypeProvider();
|
||||||
Get(MEDIA_COVER_ARTIST_ROUTE, options => GetArtistMediaCover(options.artistId, options.filename));
|
|
||||||
Get(MEDIA_COVER_ALBUM_ROUTE, options => GetAlbumMediaCover(options.artistId, options.filename));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private object GetArtistMediaCover(int artistId, string filename)
|
[HttpGet(@"artist/{artistId:int}/{filename:regex((.+)\.(jpg|png|gif))}")]
|
||||||
|
public IActionResult GetArtistMediaCover(int artistId, string filename)
|
||||||
{
|
{
|
||||||
var filePath = Path.Combine(_appFolderInfo.GetAppDataPath(), "MediaCover", artistId.ToString(), filename);
|
var filePath = Path.Combine(_appFolderInfo.GetAppDataPath(), "MediaCover", artistId.ToString(), filename);
|
||||||
|
|
||||||
|
@ -39,16 +37,17 @@ namespace Lidarr.Api.V1.MediaCovers
|
||||||
var basefilePath = RegexResizedImage.Replace(filePath, "");
|
var basefilePath = RegexResizedImage.Replace(filePath, "");
|
||||||
if (basefilePath == filePath || !_diskProvider.FileExists(basefilePath))
|
if (basefilePath == filePath || !_diskProvider.FileExists(basefilePath))
|
||||||
{
|
{
|
||||||
return new NotFoundResponse();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
filePath = basefilePath;
|
filePath = basefilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new StreamResponse(() => File.OpenRead(filePath), MimeTypes.GetMimeType(filePath));
|
return PhysicalFile(filePath, GetContentType(filePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
private object GetAlbumMediaCover(int albumId, string filename)
|
[HttpGet(@"album/{albumId:int}/{filename:regex((.+)\.(jpg|png|gif))}")]
|
||||||
|
public IActionResult GetAlbumMediaCover(int albumId, string filename)
|
||||||
{
|
{
|
||||||
var filePath = Path.Combine(_appFolderInfo.GetAppDataPath(), "MediaCover", "Albums", albumId.ToString(), filename);
|
var filePath = Path.Combine(_appFolderInfo.GetAppDataPath(), "MediaCover", "Albums", albumId.ToString(), filename);
|
||||||
|
|
||||||
|
@ -59,13 +58,23 @@ namespace Lidarr.Api.V1.MediaCovers
|
||||||
var basefilePath = RegexResizedImage.Replace(filePath, "");
|
var basefilePath = RegexResizedImage.Replace(filePath, "");
|
||||||
if (basefilePath == filePath || !_diskProvider.FileExists(basefilePath))
|
if (basefilePath == filePath || !_diskProvider.FileExists(basefilePath))
|
||||||
{
|
{
|
||||||
return new NotFoundResponse();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
filePath = basefilePath;
|
filePath = basefilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new StreamResponse(() => File.OpenRead(filePath), MimeTypes.GetMimeType(filePath));
|
return PhysicalFile(filePath, GetContentType(filePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetContentType(string filePath)
|
||||||
|
{
|
||||||
|
if (!_mimeTypeProvider.TryGetContentType(filePath, out var contentType))
|
||||||
|
{
|
||||||
|
contentType = "application/octet-stream";
|
||||||
|
}
|
||||||
|
|
||||||
|
return contentType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,14 @@
|
||||||
using NzbDrone.Core.Extras.Metadata;
|
using Lidarr.Http;
|
||||||
|
using NzbDrone.Core.Extras.Metadata;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Metadata
|
namespace Lidarr.Api.V1.Metadata
|
||||||
{
|
{
|
||||||
public class MetadataModule : ProviderModuleBase<MetadataResource, IMetadata, MetadataDefinition>
|
[V1ApiController]
|
||||||
|
public class MetadataController : ProviderControllerBase<MetadataResource, IMetadata, MetadataDefinition>
|
||||||
{
|
{
|
||||||
public static readonly MetadataResourceMapper ResourceMapper = new MetadataResourceMapper();
|
public static readonly MetadataResourceMapper ResourceMapper = new MetadataResourceMapper();
|
||||||
|
|
||||||
public MetadataModule(IMetadataFactory metadataFactory)
|
public MetadataController(IMetadataFactory metadataFactory)
|
||||||
: base(metadataFactory, "metadata", ResourceMapper)
|
: base(metadataFactory, "metadata", ResourceMapper)
|
||||||
{
|
{
|
||||||
}
|
}
|
|
@ -1,12 +1,14 @@
|
||||||
using NzbDrone.Core.Notifications;
|
using Lidarr.Http;
|
||||||
|
using NzbDrone.Core.Notifications;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Notifications
|
namespace Lidarr.Api.V1.Notifications
|
||||||
{
|
{
|
||||||
public class NotificationModule : ProviderModuleBase<NotificationResource, INotification, NotificationDefinition>
|
[V1ApiController]
|
||||||
|
public class NotificationController : ProviderControllerBase<NotificationResource, INotification, NotificationDefinition>
|
||||||
{
|
{
|
||||||
public static readonly NotificationResourceMapper ResourceMapper = new NotificationResourceMapper();
|
public static readonly NotificationResourceMapper ResourceMapper = new NotificationResourceMapper();
|
||||||
|
|
||||||
public NotificationModule(NotificationFactory notificationFactory)
|
public NotificationController(NotificationFactory notificationFactory)
|
||||||
: base(notificationFactory, "notification", ResourceMapper)
|
: base(notificationFactory, "notification", ResourceMapper)
|
||||||
{
|
{
|
||||||
}
|
}
|
|
@ -1,24 +1,24 @@
|
||||||
using Lidarr.Api.V1.Albums;
|
using Lidarr.Api.V1.Albums;
|
||||||
using Lidarr.Api.V1.Artist;
|
using Lidarr.Api.V1.Artist;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Parser;
|
using NzbDrone.Core.Parser;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Parse
|
namespace Lidarr.Api.V1.Parse
|
||||||
{
|
{
|
||||||
public class ParseModule : LidarrRestModule<ParseResource>
|
[V1ApiController]
|
||||||
|
public class ParseController : Controller
|
||||||
{
|
{
|
||||||
private readonly IParsingService _parsingService;
|
private readonly IParsingService _parsingService;
|
||||||
|
|
||||||
public ParseModule(IParsingService parsingService)
|
public ParseController(IParsingService parsingService)
|
||||||
{
|
{
|
||||||
_parsingService = parsingService;
|
_parsingService = parsingService;
|
||||||
|
|
||||||
GetResourceSingle = Parse;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ParseResource Parse()
|
[HttpGet]
|
||||||
|
public ParseResource Parse(string title)
|
||||||
{
|
{
|
||||||
var title = Request.Query.Title.Value as string;
|
|
||||||
var parsedAlbumInfo = Parser.ParseAlbumTitle(title);
|
var parsedAlbumInfo = Parser.ParseAlbumTitle(title);
|
||||||
|
|
||||||
if (parsedAlbumInfo == null)
|
if (parsedAlbumInfo == null)
|
|
@ -1,29 +1,23 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.REST;
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
using Lidarr.Http.Validation;
|
using Lidarr.Http.Validation;
|
||||||
using Nancy;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Profiles.Delay;
|
using NzbDrone.Core.Profiles.Delay;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Profiles.Delay
|
namespace Lidarr.Api.V1.Profiles.Delay
|
||||||
{
|
{
|
||||||
public class DelayProfileModule : LidarrRestModule<DelayProfileResource>
|
[V1ApiController]
|
||||||
|
public class DelayProfileController : RestController<DelayProfileResource>
|
||||||
{
|
{
|
||||||
private readonly IDelayProfileService _delayProfileService;
|
private readonly IDelayProfileService _delayProfileService;
|
||||||
|
|
||||||
public DelayProfileModule(IDelayProfileService delayProfileService, DelayProfileTagInUseValidator tagInUseValidator)
|
public DelayProfileController(IDelayProfileService delayProfileService, DelayProfileTagInUseValidator tagInUseValidator)
|
||||||
{
|
{
|
||||||
_delayProfileService = delayProfileService;
|
_delayProfileService = delayProfileService;
|
||||||
|
|
||||||
GetResourceAll = GetAll;
|
|
||||||
GetResourceById = GetById;
|
|
||||||
UpdateResource = Update;
|
|
||||||
CreateResource = Create;
|
|
||||||
DeleteResource = DeleteProfile;
|
|
||||||
Put(@"/reorder/(?<id>[\d]{1,10})", options => Reorder(options.Id));
|
|
||||||
|
|
||||||
SharedValidator.RuleFor(d => d.Tags).NotEmpty().When(d => d.Id != 1);
|
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).EmptyCollection<DelayProfileResource, int>().When(d => d.Id == 1);
|
||||||
SharedValidator.RuleFor(d => d.Tags).SetValidator(tagInUseValidator);
|
SharedValidator.RuleFor(d => d.Tags).SetValidator(tagInUseValidator);
|
||||||
|
@ -39,15 +33,17 @@ namespace Lidarr.Api.V1.Profiles.Delay
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private int Create(DelayProfileResource resource)
|
[RestPostById]
|
||||||
|
public ActionResult<DelayProfileResource> Create(DelayProfileResource resource)
|
||||||
{
|
{
|
||||||
var model = resource.ToModel();
|
var model = resource.ToModel();
|
||||||
model = _delayProfileService.Add(model);
|
model = _delayProfileService.Add(model);
|
||||||
|
|
||||||
return model.Id;
|
return Created(model.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteProfile(int id)
|
[RestDeleteById]
|
||||||
|
public void DeleteProfile(int id)
|
||||||
{
|
{
|
||||||
if (id == 1)
|
if (id == 1)
|
||||||
{
|
{
|
||||||
|
@ -57,29 +53,30 @@ namespace Lidarr.Api.V1.Profiles.Delay
|
||||||
_delayProfileService.Delete(id);
|
_delayProfileService.Delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Update(DelayProfileResource resource)
|
[RestPutById]
|
||||||
|
public ActionResult<DelayProfileResource> Update(DelayProfileResource resource)
|
||||||
{
|
{
|
||||||
var model = resource.ToModel();
|
var model = resource.ToModel();
|
||||||
_delayProfileService.Update(model);
|
_delayProfileService.Update(model);
|
||||||
|
return Accepted(model.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DelayProfileResource GetById(int id)
|
public override DelayProfileResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
return _delayProfileService.Get(id).ToResource();
|
return _delayProfileService.Get(id).ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<DelayProfileResource> GetAll()
|
[HttpGet]
|
||||||
|
public List<DelayProfileResource> GetAll()
|
||||||
{
|
{
|
||||||
return _delayProfileService.All().ToResource();
|
return _delayProfileService.All().ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private object Reorder(int id)
|
[HttpPut("reorder/{id:int}")]
|
||||||
|
public object Reorder(int id, [FromQuery] int? afterId = null)
|
||||||
{
|
{
|
||||||
ValidateId(id);
|
ValidateId(id);
|
||||||
|
|
||||||
var afterIdQuery = Request.Query.After;
|
|
||||||
int? afterId = afterIdQuery.HasValue ? Convert.ToInt32(afterIdQuery.Value) : null;
|
|
||||||
|
|
||||||
return _delayProfileService.Reorder(id, afterId).ToResource();
|
return _delayProfileService.Reorder(id, afterId).ToResource();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,54 +1,59 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Profiles.Metadata;
|
using NzbDrone.Core.Profiles.Metadata;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Profiles.Metadata
|
namespace Lidarr.Api.V1.Profiles.Metadata
|
||||||
{
|
{
|
||||||
public class MetadataProfileModule : LidarrRestModule<MetadataProfileResource>
|
[V1ApiController]
|
||||||
|
public class MetadataProfileController : RestController<MetadataProfileResource>
|
||||||
{
|
{
|
||||||
private readonly IMetadataProfileService _profileService;
|
private readonly IMetadataProfileService _profileService;
|
||||||
|
|
||||||
public MetadataProfileModule(IMetadataProfileService profileService)
|
public MetadataProfileController(IMetadataProfileService profileService)
|
||||||
{
|
{
|
||||||
_profileService = profileService;
|
_profileService = profileService;
|
||||||
|
|
||||||
SharedValidator.RuleFor(c => c.Name).NotEqual("None").WithMessage("'None' is a reserved profile name").NotEmpty();
|
SharedValidator.RuleFor(c => c.Name).NotEqual("None").WithMessage("'None' is a reserved profile name").NotEmpty();
|
||||||
SharedValidator.RuleFor(c => c.PrimaryAlbumTypes).MustHaveAllowedPrimaryType();
|
SharedValidator.RuleFor(c => c.PrimaryAlbumTypes).MustHaveAllowedPrimaryType();
|
||||||
SharedValidator.RuleFor(c => c.SecondaryAlbumTypes).MustHaveAllowedSecondaryType();
|
SharedValidator.RuleFor(c => c.SecondaryAlbumTypes).MustHaveAllowedSecondaryType();
|
||||||
SharedValidator.RuleFor(c => c.ReleaseStatuses).MustHaveAllowedReleaseStatus();
|
SharedValidator.RuleFor(c => c.ReleaseStatuses).MustHaveAllowedReleaseStatus();
|
||||||
|
|
||||||
GetResourceAll = GetAll;
|
|
||||||
GetResourceById = GetById;
|
|
||||||
UpdateResource = Update;
|
|
||||||
CreateResource = Create;
|
|
||||||
DeleteResource = DeleteProfile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int Create(MetadataProfileResource resource)
|
[RestPostById]
|
||||||
|
public ActionResult<MetadataProfileResource> Create(MetadataProfileResource resource)
|
||||||
{
|
{
|
||||||
var model = resource.ToModel();
|
var model = resource.ToModel();
|
||||||
model = _profileService.Add(model);
|
model = _profileService.Add(model);
|
||||||
return model.Id;
|
return Created(model.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteProfile(int id)
|
[RestDeleteById]
|
||||||
|
public void DeleteProfile(int id)
|
||||||
{
|
{
|
||||||
_profileService.Delete(id);
|
_profileService.Delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Update(MetadataProfileResource resource)
|
[RestPutById]
|
||||||
|
public ActionResult<MetadataProfileResource> Update(MetadataProfileResource resource)
|
||||||
{
|
{
|
||||||
var model = resource.ToModel();
|
var model = resource.ToModel();
|
||||||
|
|
||||||
_profileService.Update(model);
|
_profileService.Update(model);
|
||||||
|
|
||||||
|
return Accepted(model.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MetadataProfileResource GetById(int id)
|
public override MetadataProfileResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
return _profileService.Get(id).ToResource();
|
return _profileService.Get(id).ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MetadataProfileResource> GetAll()
|
[HttpGet]
|
||||||
|
public List<MetadataProfileResource> GetAll()
|
||||||
{
|
{
|
||||||
var profiles = _profileService.All().ToResource();
|
var profiles = _profileService.All().ToResource();
|
||||||
|
|
|
@ -1,18 +1,15 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Profiles.Metadata;
|
using NzbDrone.Core.Profiles.Metadata;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Profiles.Metadata
|
namespace Lidarr.Api.V1.Profiles.Metadata
|
||||||
{
|
{
|
||||||
public class MetadataProfileSchemaModule : LidarrRestModule<MetadataProfileResource>
|
[V1ApiController("metadataprofile/schema")]
|
||||||
|
public class MetadataProfileSchemaController : Controller
|
||||||
{
|
{
|
||||||
public MetadataProfileSchemaModule()
|
[HttpGet]
|
||||||
: base("/metadataprofile/schema")
|
public MetadataProfileResource GetAll()
|
||||||
{
|
|
||||||
GetResourceSingle = GetAll;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MetadataProfileResource GetAll()
|
|
||||||
{
|
{
|
||||||
var orderedPrimTypes = NzbDrone.Core.Music.PrimaryAlbumType.All
|
var orderedPrimTypes = NzbDrone.Core.Music.PrimaryAlbumType.All
|
||||||
.OrderByDescending(l => l.Id)
|
.OrderByDescending(l => l.Id)
|
|
@ -1,53 +1,57 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Profiles.Qualities;
|
using NzbDrone.Core.Profiles.Qualities;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Profiles.Quality
|
namespace Lidarr.Api.V1.Profiles.Quality
|
||||||
{
|
{
|
||||||
public class ProfileModule : LidarrRestModule<QualityProfileResource>
|
[V1ApiController]
|
||||||
|
public class QualityProfileController : RestController<QualityProfileResource>
|
||||||
{
|
{
|
||||||
private readonly IProfileService _profileService;
|
private readonly IProfileService _profileService;
|
||||||
|
|
||||||
public ProfileModule(IProfileService profileService)
|
public QualityProfileController(IProfileService profileService)
|
||||||
{
|
{
|
||||||
_profileService = profileService;
|
_profileService = profileService;
|
||||||
SharedValidator.RuleFor(c => c.Name).NotEmpty();
|
SharedValidator.RuleFor(c => c.Name).NotEmpty();
|
||||||
SharedValidator.RuleFor(c => c.Cutoff).ValidCutoff();
|
SharedValidator.RuleFor(c => c.Cutoff).ValidCutoff();
|
||||||
SharedValidator.RuleFor(c => c.Items).ValidItems();
|
SharedValidator.RuleFor(c => c.Items).ValidItems();
|
||||||
|
|
||||||
GetResourceAll = GetAll;
|
|
||||||
GetResourceById = GetById;
|
|
||||||
UpdateResource = Update;
|
|
||||||
CreateResource = Create;
|
|
||||||
DeleteResource = DeleteProfile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int Create(QualityProfileResource resource)
|
[RestPostById]
|
||||||
|
public ActionResult<QualityProfileResource> Create(QualityProfileResource resource)
|
||||||
{
|
{
|
||||||
var model = resource.ToModel();
|
var model = resource.ToModel();
|
||||||
model = _profileService.Add(model);
|
model = _profileService.Add(model);
|
||||||
return model.Id;
|
return Created(model.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteProfile(int id)
|
[RestDeleteById]
|
||||||
|
public void DeleteProfile(int id)
|
||||||
{
|
{
|
||||||
_profileService.Delete(id);
|
_profileService.Delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Update(QualityProfileResource resource)
|
[RestPutById]
|
||||||
|
public ActionResult<QualityProfileResource> Update(QualityProfileResource resource)
|
||||||
{
|
{
|
||||||
var model = resource.ToModel();
|
var model = resource.ToModel();
|
||||||
|
|
||||||
_profileService.Update(model);
|
_profileService.Update(model);
|
||||||
|
|
||||||
|
return Accepted(model.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private QualityProfileResource GetById(int id)
|
public override QualityProfileResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
return _profileService.Get(id).ToResource();
|
return _profileService.Get(id).ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<QualityProfileResource> GetAll()
|
[HttpGet]
|
||||||
|
public List<QualityProfileResource> GetAll()
|
||||||
{
|
{
|
||||||
return _profileService.All().ToResource();
|
return _profileService.All().ToResource();
|
||||||
}
|
}
|
|
@ -1,20 +1,21 @@
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Profiles.Qualities;
|
using NzbDrone.Core.Profiles.Qualities;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Profiles.Quality
|
namespace Lidarr.Api.V1.Profiles.Quality
|
||||||
{
|
{
|
||||||
public class QualityProfileSchemaModule : LidarrRestModule<QualityProfileResource>
|
[V1ApiController("qualityprofile/schema")]
|
||||||
|
public class QualityProfileSchemaController : Controller
|
||||||
{
|
{
|
||||||
private readonly IProfileService _profileService;
|
private readonly IProfileService _profileService;
|
||||||
|
|
||||||
public QualityProfileSchemaModule(IProfileService profileService)
|
public QualityProfileSchemaController(IProfileService profileService)
|
||||||
: base("/qualityprofile/schema")
|
|
||||||
{
|
{
|
||||||
_profileService = profileService;
|
_profileService = profileService;
|
||||||
GetResourceSingle = GetSchema;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private QualityProfileResource GetSchema()
|
[HttpGet]
|
||||||
|
public QualityProfileResource GetSchema()
|
||||||
{
|
{
|
||||||
QualityProfile qualityProfile = _profileService.GetDefaultProfile(string.Empty);
|
QualityProfile qualityProfile = _profileService.GetDefaultProfile(string.Empty);
|
||||||
|
|
|
@ -2,28 +2,26 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Profiles.Releases;
|
using NzbDrone.Core.Profiles.Releases;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Profiles.Release
|
namespace Lidarr.Api.V1.Profiles.Release
|
||||||
{
|
{
|
||||||
public class ReleaseProfileModule : LidarrRestModule<ReleaseProfileResource>
|
[V1ApiController]
|
||||||
|
public class ReleaseProfileController : RestController<ReleaseProfileResource>
|
||||||
{
|
{
|
||||||
private readonly IReleaseProfileService _releaseProfileService;
|
private readonly IReleaseProfileService _releaseProfileService;
|
||||||
private readonly IIndexerFactory _indexerFactory;
|
private readonly IIndexerFactory _indexerFactory;
|
||||||
|
|
||||||
public ReleaseProfileModule(IReleaseProfileService releaseProfileService, IIndexerFactory indexerFactory)
|
public ReleaseProfileController(IReleaseProfileService releaseProfileService, IIndexerFactory indexerFactory)
|
||||||
{
|
{
|
||||||
_releaseProfileService = releaseProfileService;
|
_releaseProfileService = releaseProfileService;
|
||||||
_indexerFactory = indexerFactory;
|
_indexerFactory = indexerFactory;
|
||||||
|
|
||||||
GetResourceById = GetById;
|
|
||||||
GetResourceAll = GetAll;
|
|
||||||
CreateResource = Create;
|
|
||||||
UpdateResource = Update;
|
|
||||||
DeleteResource = DeleteById;
|
|
||||||
|
|
||||||
SharedValidator.RuleFor(r => r).Custom((restriction, context) =>
|
SharedValidator.RuleFor(r => r).Custom((restriction, context) =>
|
||||||
{
|
{
|
||||||
if (restriction.Ignored.IsNullOrWhiteSpace() && restriction.Required.IsNullOrWhiteSpace() && restriction.Preferred.Empty())
|
if (restriction.Ignored.IsNullOrWhiteSpace() && restriction.Required.IsNullOrWhiteSpace() && restriction.Preferred.Empty())
|
||||||
|
@ -43,27 +41,32 @@ namespace Lidarr.Api.V1.Profiles.Release
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReleaseProfileResource GetById(int id)
|
public override ReleaseProfileResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
return _releaseProfileService.Get(id).ToResource();
|
return _releaseProfileService.Get(id).ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ReleaseProfileResource> GetAll()
|
[HttpGet]
|
||||||
|
public List<ReleaseProfileResource> GetAll()
|
||||||
{
|
{
|
||||||
return _releaseProfileService.All().ToResource();
|
return _releaseProfileService.All().ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int Create(ReleaseProfileResource resource)
|
[RestPostById]
|
||||||
|
public ActionResult<ReleaseProfileResource> Create(ReleaseProfileResource resource)
|
||||||
{
|
{
|
||||||
return _releaseProfileService.Add(resource.ToModel()).Id;
|
return Created(_releaseProfileService.Add(resource.ToModel()).Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Update(ReleaseProfileResource resource)
|
[RestPutById]
|
||||||
|
public ActionResult<ReleaseProfileResource> Update(ReleaseProfileResource resource)
|
||||||
{
|
{
|
||||||
_releaseProfileService.Update(resource.ToModel());
|
_releaseProfileService.Update(resource.ToModel());
|
||||||
|
return Accepted(resource.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteById(int id)
|
[RestDeleteById]
|
||||||
|
public void DeleteById(int id)
|
||||||
{
|
{
|
||||||
_releaseProfileService.Delete(id);
|
_releaseProfileService.Delete(id);
|
||||||
}
|
}
|
|
@ -2,15 +2,16 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using FluentValidation.Results;
|
using FluentValidation.Results;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http.REST;
|
||||||
using Nancy;
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common.Serializer;
|
using NzbDrone.Common.Serializer;
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1
|
namespace Lidarr.Api.V1
|
||||||
{
|
{
|
||||||
public abstract class ProviderModuleBase<TProviderResource, TProvider, TProviderDefinition> : LidarrRestModule<TProviderResource>
|
public abstract class ProviderControllerBase<TProviderResource, TProvider, TProviderDefinition> : RestController<TProviderResource>
|
||||||
where TProviderDefinition : ProviderDefinition, new()
|
where TProviderDefinition : ProviderDefinition, new()
|
||||||
where TProvider : IProvider
|
where TProvider : IProvider
|
||||||
where TProviderResource : ProviderResource<TProviderResource>, new()
|
where TProviderResource : ProviderResource<TProviderResource>, new()
|
||||||
|
@ -18,23 +19,11 @@ namespace Lidarr.Api.V1
|
||||||
private readonly IProviderFactory<TProvider, TProviderDefinition> _providerFactory;
|
private readonly IProviderFactory<TProvider, TProviderDefinition> _providerFactory;
|
||||||
private readonly ProviderResourceMapper<TProviderResource, TProviderDefinition> _resourceMapper;
|
private readonly ProviderResourceMapper<TProviderResource, TProviderDefinition> _resourceMapper;
|
||||||
|
|
||||||
protected ProviderModuleBase(IProviderFactory<TProvider, TProviderDefinition> providerFactory, string resource, ProviderResourceMapper<TProviderResource, TProviderDefinition> resourceMapper)
|
protected ProviderControllerBase(IProviderFactory<TProvider, TProviderDefinition> providerFactory, string resource, ProviderResourceMapper<TProviderResource, TProviderDefinition> resourceMapper)
|
||||||
: base(resource)
|
|
||||||
{
|
{
|
||||||
_providerFactory = providerFactory;
|
_providerFactory = providerFactory;
|
||||||
_resourceMapper = resourceMapper;
|
_resourceMapper = resourceMapper;
|
||||||
|
|
||||||
Get("schema", x => GetTemplates());
|
|
||||||
Post("test", x => Test(ReadResourceFromRequest(true)));
|
|
||||||
Post("testall", x => TestAll());
|
|
||||||
Post("action/{action}", x => RequestAction(x.action, ReadResourceFromRequest(true, true)));
|
|
||||||
|
|
||||||
GetResourceAll = GetAll;
|
|
||||||
GetResourceById = GetProviderById;
|
|
||||||
CreateResource = CreateProvider;
|
|
||||||
UpdateResource = UpdateProvider;
|
|
||||||
DeleteResource = DeleteProvider;
|
|
||||||
|
|
||||||
SharedValidator.RuleFor(c => c.Name).NotEmpty();
|
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.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.Implementation).NotEmpty();
|
||||||
|
@ -43,7 +32,7 @@ namespace Lidarr.Api.V1
|
||||||
PostValidator.RuleFor(c => c.Fields).NotNull();
|
PostValidator.RuleFor(c => c.Fields).NotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
private TProviderResource GetProviderById(int id)
|
public override TProviderResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
var definition = _providerFactory.Get(id);
|
var definition = _providerFactory.Get(id);
|
||||||
_providerFactory.SetProviderCharacteristics(definition);
|
_providerFactory.SetProviderCharacteristics(definition);
|
||||||
|
@ -51,7 +40,8 @@ namespace Lidarr.Api.V1
|
||||||
return _resourceMapper.ToResource(definition);
|
return _resourceMapper.ToResource(definition);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TProviderResource> GetAll()
|
[HttpGet]
|
||||||
|
public List<TProviderResource> GetAll()
|
||||||
{
|
{
|
||||||
var providerDefinitions = _providerFactory.All().OrderBy(p => p.ImplementationName);
|
var providerDefinitions = _providerFactory.All().OrderBy(p => p.ImplementationName);
|
||||||
|
|
||||||
|
@ -67,7 +57,8 @@ namespace Lidarr.Api.V1
|
||||||
return result.OrderBy(p => p.Name).ToList();
|
return result.OrderBy(p => p.Name).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int CreateProvider(TProviderResource providerResource)
|
[RestPostById]
|
||||||
|
public ActionResult<TProviderResource> CreateProvider(TProviderResource providerResource)
|
||||||
{
|
{
|
||||||
var providerDefinition = GetDefinition(providerResource, false);
|
var providerDefinition = GetDefinition(providerResource, false);
|
||||||
|
|
||||||
|
@ -78,10 +69,11 @@ namespace Lidarr.Api.V1
|
||||||
|
|
||||||
providerDefinition = _providerFactory.Create(providerDefinition);
|
providerDefinition = _providerFactory.Create(providerDefinition);
|
||||||
|
|
||||||
return providerDefinition.Id;
|
return Created(providerDefinition.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateProvider(TProviderResource providerResource)
|
[RestPutById]
|
||||||
|
public ActionResult<TProviderResource> UpdateProvider(TProviderResource providerResource)
|
||||||
{
|
{
|
||||||
var providerDefinition = GetDefinition(providerResource, false);
|
var providerDefinition = GetDefinition(providerResource, false);
|
||||||
var existingDefinition = _providerFactory.Get(providerDefinition.Id);
|
var existingDefinition = _providerFactory.Get(providerDefinition.Id);
|
||||||
|
@ -93,6 +85,8 @@ namespace Lidarr.Api.V1
|
||||||
}
|
}
|
||||||
|
|
||||||
_providerFactory.Update(providerDefinition);
|
_providerFactory.Update(providerDefinition);
|
||||||
|
|
||||||
|
return Accepted(providerResource.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TProviderDefinition GetDefinition(TProviderResource providerResource, bool includeWarnings = false, bool validate = true)
|
private TProviderDefinition GetDefinition(TProviderResource providerResource, bool includeWarnings = false, bool validate = true)
|
||||||
|
@ -107,12 +101,14 @@ namespace Lidarr.Api.V1
|
||||||
return definition;
|
return definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteProvider(int id)
|
[RestDeleteById]
|
||||||
|
public void DeleteProvider(int id)
|
||||||
{
|
{
|
||||||
_providerFactory.Delete(id);
|
_providerFactory.Delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private object GetTemplates()
|
[HttpGet("schema")]
|
||||||
|
public List<TProviderResource> GetTemplates()
|
||||||
{
|
{
|
||||||
var defaultDefinitions = _providerFactory.GetDefaultDefinitions().OrderBy(p => p.ImplementationName).ToList();
|
var defaultDefinitions = _providerFactory.GetDefaultDefinitions().OrderBy(p => p.ImplementationName).ToList();
|
||||||
|
|
||||||
|
@ -133,7 +129,9 @@ namespace Lidarr.Api.V1
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private object Test(TProviderResource providerResource)
|
[SkipValidation(true, false)]
|
||||||
|
[HttpPost("test")]
|
||||||
|
public object Test([FromBody] TProviderResource providerResource)
|
||||||
{
|
{
|
||||||
var providerDefinition = GetDefinition(providerResource, true);
|
var providerDefinition = GetDefinition(providerResource, true);
|
||||||
|
|
||||||
|
@ -142,7 +140,8 @@ namespace Lidarr.Api.V1
|
||||||
return "{}";
|
return "{}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private object TestAll()
|
[HttpPost("testall")]
|
||||||
|
public IActionResult TestAll()
|
||||||
{
|
{
|
||||||
var providerDefinitions = _providerFactory.All()
|
var providerDefinitions = _providerFactory.All()
|
||||||
.Where(c => c.Settings.Validate().IsValid && c.Enable)
|
.Where(c => c.Settings.Validate().IsValid && c.Enable)
|
||||||
|
@ -160,19 +159,20 @@ namespace Lidarr.Api.V1
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResponseWithCode(result, result.Any(c => !c.IsValid) ? HttpStatusCode.BadRequest : HttpStatusCode.OK);
|
return result.Any(c => !c.IsValid) ? BadRequest(result) : Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private object RequestAction(string action, TProviderResource providerResource)
|
[SkipValidation]
|
||||||
|
[HttpPost("action/{name}")]
|
||||||
|
public IActionResult RequestAction(string name, [FromBody] TProviderResource resource)
|
||||||
{
|
{
|
||||||
var providerDefinition = GetDefinition(providerResource, true, false);
|
var providerDefinition = GetDefinition(resource, true, false);
|
||||||
|
|
||||||
var query = ((IDictionary<string, object>)Request.Query.ToDictionary()).ToDictionary(k => k.Key, k => k.Value.ToString());
|
var query = Request.Query.ToDictionary(x => x.Key, x => x.Value.ToString());
|
||||||
|
|
||||||
var data = _providerFactory.RequestAction(providerDefinition, action, query);
|
var data = _providerFactory.RequestAction(providerDefinition, name, query);
|
||||||
Response resp = data.ToJson();
|
|
||||||
resp.ContentType = "application/json";
|
return Content(data.ToJson(), "application/json");
|
||||||
return resp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Validate(TProviderDefinition definition, bool includeWarnings)
|
protected virtual void Validate(TProviderDefinition definition, bool includeWarnings)
|
54
src/Lidarr.Api.V1/Qualities/QualityDefinitionController.cs
Normal file
54
src/Lidarr.Api.V1/Qualities/QualityDefinitionController.cs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
|
namespace Lidarr.Api.V1.Qualities
|
||||||
|
{
|
||||||
|
[V1ApiController]
|
||||||
|
public class QualityDefinitionController : RestController<QualityDefinitionResource>
|
||||||
|
{
|
||||||
|
private readonly IQualityDefinitionService _qualityDefinitionService;
|
||||||
|
|
||||||
|
public QualityDefinitionController(IQualityDefinitionService qualityDefinitionService)
|
||||||
|
{
|
||||||
|
_qualityDefinitionService = qualityDefinitionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RestPutById]
|
||||||
|
public ActionResult<QualityDefinitionResource> Update(QualityDefinitionResource resource)
|
||||||
|
{
|
||||||
|
var model = resource.ToModel();
|
||||||
|
_qualityDefinitionService.Update(model);
|
||||||
|
return Accepted(model.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override QualityDefinitionResource GetResourceById(int id)
|
||||||
|
{
|
||||||
|
return _qualityDefinitionService.GetById(id).ToResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public List<QualityDefinitionResource> GetAll()
|
||||||
|
{
|
||||||
|
return _qualityDefinitionService.All().ToResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("update")]
|
||||||
|
public object UpdateMany([FromBody] List<QualityDefinitionResource> resource)
|
||||||
|
{
|
||||||
|
//Read from request
|
||||||
|
var qualityDefinitions = resource
|
||||||
|
.ToModel()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
_qualityDefinitionService.UpdateMany(qualityDefinitions);
|
||||||
|
|
||||||
|
return Accepted(_qualityDefinitionService.All()
|
||||||
|
.ToResource());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,54 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Lidarr.Http;
|
|
||||||
using Lidarr.Http.Extensions;
|
|
||||||
using Nancy;
|
|
||||||
using NzbDrone.Core.Qualities;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Qualities
|
|
||||||
{
|
|
||||||
public class QualityDefinitionModule : LidarrRestModule<QualityDefinitionResource>
|
|
||||||
{
|
|
||||||
private readonly IQualityDefinitionService _qualityDefinitionService;
|
|
||||||
|
|
||||||
public QualityDefinitionModule(IQualityDefinitionService qualityDefinitionService)
|
|
||||||
{
|
|
||||||
_qualityDefinitionService = qualityDefinitionService;
|
|
||||||
|
|
||||||
GetResourceAll = GetAll;
|
|
||||||
GetResourceById = GetById;
|
|
||||||
UpdateResource = Update;
|
|
||||||
Put("/update", d => UpdateMany());
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
private object UpdateMany()
|
|
||||||
{
|
|
||||||
//Read from request
|
|
||||||
var qualityDefinitions = Request.Body.FromJson<List<QualityDefinitionResource>>()
|
|
||||||
.ToModel()
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
_qualityDefinitionService.UpdateMany(qualityDefinitions);
|
|
||||||
|
|
||||||
return ResponseWithCode(_qualityDefinitionService.All()
|
|
||||||
.ToResource(),
|
|
||||||
HttpStatusCode.Accepted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
55
src/Lidarr.Api.V1/Queue/QueueActionController.cs
Normal file
55
src/Lidarr.Api.V1/Queue/QueueActionController.cs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
|
using NzbDrone.Core.Download.Pending;
|
||||||
|
|
||||||
|
namespace Lidarr.Api.V1.Queue
|
||||||
|
{
|
||||||
|
[V1ApiController("queue")]
|
||||||
|
public class QueueActionController : Controller
|
||||||
|
{
|
||||||
|
private readonly IPendingReleaseService _pendingReleaseService;
|
||||||
|
private readonly IDownloadService _downloadService;
|
||||||
|
|
||||||
|
public QueueActionController(IPendingReleaseService pendingReleaseService,
|
||||||
|
IDownloadService downloadService)
|
||||||
|
{
|
||||||
|
_pendingReleaseService = pendingReleaseService;
|
||||||
|
_downloadService = downloadService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("grab/{id:int}")]
|
||||||
|
public object Grab(int id)
|
||||||
|
{
|
||||||
|
var pendingRelease = _pendingReleaseService.FindPendingQueueItem(id);
|
||||||
|
|
||||||
|
if (pendingRelease == null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
_downloadService.DownloadReport(pendingRelease.RemoteAlbum);
|
||||||
|
|
||||||
|
return new object();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("grab/bulk")]
|
||||||
|
public object Grab([FromBody] QueueBulkResource resource)
|
||||||
|
{
|
||||||
|
foreach (var id in resource.Ids)
|
||||||
|
{
|
||||||
|
var pendingRelease = _pendingReleaseService.FindPendingQueueItem(id);
|
||||||
|
|
||||||
|
if (pendingRelease == null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
_downloadService.DownloadReport(pendingRelease.RemoteAlbum);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,184 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using Lidarr.Http;
|
|
||||||
using Lidarr.Http.Extensions;
|
|
||||||
using Lidarr.Http.REST;
|
|
||||||
using Nancy;
|
|
||||||
using NzbDrone.Core.Download;
|
|
||||||
using NzbDrone.Core.Download.Pending;
|
|
||||||
using NzbDrone.Core.Download.TrackedDownloads;
|
|
||||||
using NzbDrone.Core.Queue;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Queue
|
|
||||||
{
|
|
||||||
public class QueueActionModule : LidarrRestModule<QueueResource>
|
|
||||||
{
|
|
||||||
private readonly IQueueService _queueService;
|
|
||||||
private readonly ITrackedDownloadService _trackedDownloadService;
|
|
||||||
private readonly IFailedDownloadService _failedDownloadService;
|
|
||||||
private readonly IIgnoredDownloadService _ignoredDownloadService;
|
|
||||||
private readonly IProvideDownloadClient _downloadClientProvider;
|
|
||||||
private readonly IPendingReleaseService _pendingReleaseService;
|
|
||||||
private readonly IDownloadService _downloadService;
|
|
||||||
|
|
||||||
public QueueActionModule(IQueueService queueService,
|
|
||||||
ITrackedDownloadService trackedDownloadService,
|
|
||||||
IFailedDownloadService failedDownloadService,
|
|
||||||
IIgnoredDownloadService ignoredDownloadService,
|
|
||||||
IProvideDownloadClient downloadClientProvider,
|
|
||||||
IPendingReleaseService pendingReleaseService,
|
|
||||||
IDownloadService downloadService)
|
|
||||||
{
|
|
||||||
_queueService = queueService;
|
|
||||||
_trackedDownloadService = trackedDownloadService;
|
|
||||||
_failedDownloadService = failedDownloadService;
|
|
||||||
_ignoredDownloadService = ignoredDownloadService;
|
|
||||||
_downloadClientProvider = downloadClientProvider;
|
|
||||||
_pendingReleaseService = pendingReleaseService;
|
|
||||||
_downloadService = downloadService;
|
|
||||||
|
|
||||||
Post(@"/grab/(?<id>[\d]{1,10})", x => Grab((int)x.Id));
|
|
||||||
Post("/grab/bulk", x => Grab());
|
|
||||||
|
|
||||||
Delete(@"/(?<id>[\d]{1,10})", x => Remove((int)x.Id));
|
|
||||||
Delete("/bulk", x => Remove());
|
|
||||||
}
|
|
||||||
|
|
||||||
private object Grab(int id)
|
|
||||||
{
|
|
||||||
var pendingRelease = _pendingReleaseService.FindPendingQueueItem(id);
|
|
||||||
|
|
||||||
if (pendingRelease == null)
|
|
||||||
{
|
|
||||||
throw new NotFoundException();
|
|
||||||
}
|
|
||||||
|
|
||||||
_downloadService.DownloadReport(pendingRelease.RemoteAlbum);
|
|
||||||
|
|
||||||
return new object();
|
|
||||||
}
|
|
||||||
|
|
||||||
private object Grab()
|
|
||||||
{
|
|
||||||
var resource = Request.Body.FromJson<QueueBulkResource>();
|
|
||||||
|
|
||||||
foreach (var id in resource.Ids)
|
|
||||||
{
|
|
||||||
var pendingRelease = _pendingReleaseService.FindPendingQueueItem(id);
|
|
||||||
|
|
||||||
if (pendingRelease == null)
|
|
||||||
{
|
|
||||||
throw new NotFoundException();
|
|
||||||
}
|
|
||||||
|
|
||||||
_downloadService.DownloadReport(pendingRelease.RemoteAlbum);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new object();
|
|
||||||
}
|
|
||||||
|
|
||||||
private object Remove(int id)
|
|
||||||
{
|
|
||||||
var removeFromClient = Request.GetBooleanQueryParameter("removeFromClient", true);
|
|
||||||
var blacklist = Request.GetBooleanQueryParameter("blacklist");
|
|
||||||
var skipReDownload = Request.GetBooleanQueryParameter("skipredownload");
|
|
||||||
|
|
||||||
var trackedDownload = Remove(id, removeFromClient, blacklist, skipReDownload);
|
|
||||||
|
|
||||||
if (trackedDownload != null)
|
|
||||||
{
|
|
||||||
_trackedDownloadService.StopTracking(trackedDownload.DownloadItem.DownloadId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new object();
|
|
||||||
}
|
|
||||||
|
|
||||||
private object Remove()
|
|
||||||
{
|
|
||||||
var removeFromClient = Request.GetBooleanQueryParameter("removeFromClient", true);
|
|
||||||
var blacklist = Request.GetBooleanQueryParameter("blacklist");
|
|
||||||
var skipReDownload = Request.GetBooleanQueryParameter("skipredownload");
|
|
||||||
|
|
||||||
var resource = Request.Body.FromJson<QueueBulkResource>();
|
|
||||||
var trackedDownloadIds = new List<string>();
|
|
||||||
|
|
||||||
foreach (var id in resource.Ids)
|
|
||||||
{
|
|
||||||
var trackedDownload = Remove(id, removeFromClient, blacklist, skipReDownload);
|
|
||||||
|
|
||||||
if (trackedDownload != null)
|
|
||||||
{
|
|
||||||
trackedDownloadIds.Add(trackedDownload.DownloadItem.DownloadId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_trackedDownloadService.StopTracking(trackedDownloadIds);
|
|
||||||
|
|
||||||
return new object();
|
|
||||||
}
|
|
||||||
|
|
||||||
private TrackedDownload Remove(int id, bool removeFromClient, bool blacklist, bool skipReDownload)
|
|
||||||
{
|
|
||||||
var pendingRelease = _pendingReleaseService.FindPendingQueueItem(id);
|
|
||||||
|
|
||||||
if (pendingRelease != null)
|
|
||||||
{
|
|
||||||
_pendingReleaseService.RemovePendingQueueItems(pendingRelease.Id);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var trackedDownload = GetTrackedDownload(id);
|
|
||||||
|
|
||||||
if (trackedDownload == null)
|
|
||||||
{
|
|
||||||
throw new NotFoundException();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (removeFromClient)
|
|
||||||
{
|
|
||||||
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, skipReDownload);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!removeFromClient && !blacklist)
|
|
||||||
{
|
|
||||||
if (!_ignoredDownloadService.IgnoreDownload(trackedDownload))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return trackedDownload;
|
|
||||||
}
|
|
||||||
|
|
||||||
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,11 +1,17 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.Extensions;
|
using Lidarr.Http.Extensions;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
using NzbDrone.Core.Datastore.Events;
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.Download.Pending;
|
using NzbDrone.Core.Download.Pending;
|
||||||
|
using NzbDrone.Core.Download.TrackedDownloads;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Profiles.Qualities;
|
using NzbDrone.Core.Profiles.Qualities;
|
||||||
using NzbDrone.Core.Qualities;
|
using NzbDrone.Core.Qualities;
|
||||||
|
@ -14,35 +20,82 @@ using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Queue
|
namespace Lidarr.Api.V1.Queue
|
||||||
{
|
{
|
||||||
public class QueueModule : LidarrRestModuleWithSignalR<QueueResource, NzbDrone.Core.Queue.Queue>,
|
[V1ApiController]
|
||||||
|
public class QueueController : RestControllerWithSignalR<QueueResource, NzbDrone.Core.Queue.Queue>,
|
||||||
IHandle<QueueUpdatedEvent>, IHandle<PendingReleasesUpdatedEvent>
|
IHandle<QueueUpdatedEvent>, IHandle<PendingReleasesUpdatedEvent>
|
||||||
{
|
{
|
||||||
private readonly IQueueService _queueService;
|
private readonly IQueueService _queueService;
|
||||||
private readonly IPendingReleaseService _pendingReleaseService;
|
private readonly IPendingReleaseService _pendingReleaseService;
|
||||||
|
|
||||||
private readonly QualityModelComparer _qualityComparer;
|
private readonly QualityModelComparer _qualityComparer;
|
||||||
|
private readonly ITrackedDownloadService _trackedDownloadService;
|
||||||
|
private readonly IFailedDownloadService _failedDownloadService;
|
||||||
|
private readonly IIgnoredDownloadService _ignoredDownloadService;
|
||||||
|
private readonly IProvideDownloadClient _downloadClientProvider;
|
||||||
|
|
||||||
public QueueModule(IBroadcastSignalRMessage broadcastSignalRMessage,
|
public QueueController(IBroadcastSignalRMessage broadcastSignalRMessage,
|
||||||
IQueueService queueService,
|
IQueueService queueService,
|
||||||
IPendingReleaseService pendingReleaseService,
|
IPendingReleaseService pendingReleaseService,
|
||||||
QualityProfileService qualityProfileService)
|
QualityProfileService qualityProfileService,
|
||||||
|
ITrackedDownloadService trackedDownloadService,
|
||||||
|
IFailedDownloadService failedDownloadService,
|
||||||
|
IIgnoredDownloadService ignoredDownloadService,
|
||||||
|
IProvideDownloadClient downloadClientProvider)
|
||||||
: base(broadcastSignalRMessage)
|
: base(broadcastSignalRMessage)
|
||||||
{
|
{
|
||||||
_queueService = queueService;
|
_queueService = queueService;
|
||||||
_pendingReleaseService = pendingReleaseService;
|
_pendingReleaseService = pendingReleaseService;
|
||||||
GetResourcePaged = GetQueue;
|
_trackedDownloadService = trackedDownloadService;
|
||||||
|
_failedDownloadService = failedDownloadService;
|
||||||
|
_ignoredDownloadService = ignoredDownloadService;
|
||||||
|
_downloadClientProvider = downloadClientProvider;
|
||||||
|
|
||||||
_qualityComparer = new QualityModelComparer(qualityProfileService.GetDefaultProfile(string.Empty));
|
_qualityComparer = new QualityModelComparer(qualityProfileService.GetDefaultProfile(string.Empty));
|
||||||
}
|
}
|
||||||
|
|
||||||
private PagingResource<QueueResource> GetQueue(PagingResource<QueueResource> pagingResource)
|
public override QueueResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
var pagingSpec = pagingResource.MapToPagingSpec<QueueResource, NzbDrone.Core.Queue.Queue>("timeleft", SortDirection.Ascending);
|
throw new NotImplementedException();
|
||||||
var includeUnknownArtistItems = Request.GetBooleanQueryParameter("includeUnknownArtistItems");
|
}
|
||||||
var includeArtist = Request.GetBooleanQueryParameter("includeArtist");
|
|
||||||
var includeAlbum = Request.GetBooleanQueryParameter("includeAlbum");
|
|
||||||
|
|
||||||
return ApplyToPage((spec) => GetQueue(spec, includeUnknownArtistItems), pagingSpec, (q) => MapToResource(q, includeArtist, includeAlbum));
|
[RestDeleteById]
|
||||||
|
public void RemoveAction(int id, bool removeFromClient = true, bool blacklist = false, bool skipReDownload = false)
|
||||||
|
{
|
||||||
|
var trackedDownload = Remove(id, removeFromClient, blacklist, skipReDownload);
|
||||||
|
|
||||||
|
if (trackedDownload != null)
|
||||||
|
{
|
||||||
|
_trackedDownloadService.StopTracking(trackedDownload.DownloadItem.DownloadId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("bulk")]
|
||||||
|
public object RemoveMany([FromBody] QueueBulkResource resource, [FromQuery] bool removeFromClient = true, [FromQuery] bool blacklist = false, [FromQuery] bool skipReDownload = false)
|
||||||
|
{
|
||||||
|
var trackedDownloadIds = new List<string>();
|
||||||
|
|
||||||
|
foreach (var id in resource.Ids)
|
||||||
|
{
|
||||||
|
var trackedDownload = Remove(id, removeFromClient, blacklist, skipReDownload);
|
||||||
|
|
||||||
|
if (trackedDownload != null)
|
||||||
|
{
|
||||||
|
trackedDownloadIds.Add(trackedDownload.DownloadItem.DownloadId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_trackedDownloadService.StopTracking(trackedDownloadIds);
|
||||||
|
|
||||||
|
return new object();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public PagingResource<QueueResource> GetQueue(bool includeUnknownArtistItems = false, bool includeArtist = false, bool includeAlbum = false)
|
||||||
|
{
|
||||||
|
var pagingResource = Request.ReadPagingResourceFromRequest<QueueResource>();
|
||||||
|
var pagingSpec = pagingResource.MapToPagingSpec<QueueResource, NzbDrone.Core.Queue.Queue>("timeleft", SortDirection.Ascending);
|
||||||
|
|
||||||
|
return pagingSpec.ApplyToPage((spec) => GetQueue(spec, includeUnknownArtistItems), (q) => MapToResource(q, includeArtist, includeAlbum));
|
||||||
}
|
}
|
||||||
|
|
||||||
private PagingSpec<NzbDrone.Core.Queue.Queue> GetQueue(PagingSpec<NzbDrone.Core.Queue.Queue> pagingSpec, bool includeUnknownArtistItems)
|
private PagingSpec<NzbDrone.Core.Queue.Queue> GetQueue(PagingSpec<NzbDrone.Core.Queue.Queue> pagingSpec, bool includeUnknownArtistItems)
|
||||||
|
@ -138,16 +191,83 @@ namespace Lidarr.Api.V1.Queue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TrackedDownload Remove(int id, bool removeFromClient, bool blacklist, bool skipReDownload)
|
||||||
|
{
|
||||||
|
var pendingRelease = _pendingReleaseService.FindPendingQueueItem(id);
|
||||||
|
|
||||||
|
if (pendingRelease != null)
|
||||||
|
{
|
||||||
|
_pendingReleaseService.RemovePendingQueueItems(pendingRelease.Id);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var trackedDownload = GetTrackedDownload(id);
|
||||||
|
|
||||||
|
if (trackedDownload == null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removeFromClient)
|
||||||
|
{
|
||||||
|
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, skipReDownload);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!removeFromClient && !blacklist)
|
||||||
|
{
|
||||||
|
if (!_ignoredDownloadService.IgnoreDownload(trackedDownload))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return trackedDownload;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
private QueueResource MapToResource(NzbDrone.Core.Queue.Queue queueItem, bool includeArtist, bool includeAlbum)
|
private QueueResource MapToResource(NzbDrone.Core.Queue.Queue queueItem, bool includeArtist, bool includeAlbum)
|
||||||
{
|
{
|
||||||
return queueItem.ToResource(includeArtist, includeAlbum);
|
return queueItem.ToResource(includeArtist, includeAlbum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(QueueUpdatedEvent message)
|
public void Handle(QueueUpdatedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Sync);
|
BroadcastResourceChange(ModelAction.Sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(PendingReleasesUpdatedEvent message)
|
public void Handle(PendingReleasesUpdatedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Sync);
|
BroadcastResourceChange(ModelAction.Sync);
|
|
@ -2,7 +2,8 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.Extensions;
|
using Lidarr.Http.REST;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
using NzbDrone.Core.Datastore.Events;
|
||||||
using NzbDrone.Core.Download.Pending;
|
using NzbDrone.Core.Download.Pending;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
@ -11,55 +12,52 @@ using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Queue
|
namespace Lidarr.Api.V1.Queue
|
||||||
{
|
{
|
||||||
public class QueueDetailsModule : LidarrRestModuleWithSignalR<QueueResource, NzbDrone.Core.Queue.Queue>,
|
[V1ApiController("queue/details")]
|
||||||
|
public class QueueDetailsController : RestControllerWithSignalR<QueueResource, NzbDrone.Core.Queue.Queue>,
|
||||||
IHandle<QueueUpdatedEvent>, IHandle<PendingReleasesUpdatedEvent>
|
IHandle<QueueUpdatedEvent>, IHandle<PendingReleasesUpdatedEvent>
|
||||||
{
|
{
|
||||||
private readonly IQueueService _queueService;
|
private readonly IQueueService _queueService;
|
||||||
private readonly IPendingReleaseService _pendingReleaseService;
|
private readonly IPendingReleaseService _pendingReleaseService;
|
||||||
|
|
||||||
public QueueDetailsModule(IBroadcastSignalRMessage broadcastSignalRMessage, IQueueService queueService, IPendingReleaseService pendingReleaseService)
|
public QueueDetailsController(IBroadcastSignalRMessage broadcastSignalRMessage, IQueueService queueService, IPendingReleaseService pendingReleaseService)
|
||||||
: base(broadcastSignalRMessage, "queue/details")
|
: base(broadcastSignalRMessage)
|
||||||
{
|
{
|
||||||
_queueService = queueService;
|
_queueService = queueService;
|
||||||
_pendingReleaseService = pendingReleaseService;
|
_pendingReleaseService = pendingReleaseService;
|
||||||
GetResourceAll = GetQueue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<QueueResource> GetQueue()
|
public override QueueResource GetResourceById(int id)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public List<QueueResource> GetQueue(int? artistId, [FromQuery]List<int> albumIds, bool includeArtist = false, bool includeAlbum = true)
|
||||||
{
|
{
|
||||||
var includeArtist = Request.GetBooleanQueryParameter("includeArtist");
|
|
||||||
var includeAlbum = Request.GetBooleanQueryParameter("includeAlbum", true);
|
|
||||||
var queue = _queueService.GetQueue();
|
var queue = _queueService.GetQueue();
|
||||||
var pending = _pendingReleaseService.GetPendingQueue();
|
var pending = _pendingReleaseService.GetPendingQueue();
|
||||||
var fullQueue = queue.Concat(pending);
|
var fullQueue = queue.Concat(pending);
|
||||||
|
|
||||||
var artistIdQuery = Request.Query.ArtistId;
|
if (artistId.HasValue)
|
||||||
var albumIdsQuery = Request.Query.AlbumIds;
|
|
||||||
|
|
||||||
if (artistIdQuery.HasValue)
|
|
||||||
{
|
{
|
||||||
return fullQueue.Where(q => q.Artist?.Id == (int)artistIdQuery).ToResource(includeArtist, includeAlbum);
|
return fullQueue.Where(q => q.Artist?.Id == artistId.Value).ToResource(includeArtist, includeAlbum);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (albumIdsQuery.HasValue)
|
if (albumIds.Any())
|
||||||
{
|
{
|
||||||
string albumIdsValue = albumIdsQuery.Value.ToString();
|
|
||||||
|
|
||||||
var albumIds = albumIdsValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Select(e => Convert.ToInt32(e))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
return fullQueue.Where(q => q.Album != null && albumIds.Contains(q.Album.Id)).ToResource(includeArtist, includeAlbum);
|
return fullQueue.Where(q => q.Album != null && albumIds.Contains(q.Album.Id)).ToResource(includeArtist, includeAlbum);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fullQueue.ToResource(includeArtist, includeAlbum);
|
return fullQueue.ToResource(includeArtist, includeAlbum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(QueueUpdatedEvent message)
|
public void Handle(QueueUpdatedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Sync);
|
BroadcastResourceChange(ModelAction.Sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(PendingReleasesUpdatedEvent message)
|
public void Handle(PendingReleasesUpdatedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Sync);
|
BroadcastResourceChange(ModelAction.Sync);
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common.TPL;
|
using NzbDrone.Common.TPL;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
using NzbDrone.Core.Datastore.Events;
|
||||||
using NzbDrone.Core.Download.Pending;
|
using NzbDrone.Core.Download.Pending;
|
||||||
|
@ -11,30 +13,30 @@ using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Queue
|
namespace Lidarr.Api.V1.Queue
|
||||||
{
|
{
|
||||||
public class QueueStatusModule : LidarrRestModuleWithSignalR<QueueStatusResource, NzbDrone.Core.Queue.Queue>,
|
[V1ApiController("queue/status")]
|
||||||
|
public class QueueStatusController : RestControllerWithSignalR<QueueStatusResource, NzbDrone.Core.Queue.Queue>,
|
||||||
IHandle<QueueUpdatedEvent>, IHandle<PendingReleasesUpdatedEvent>
|
IHandle<QueueUpdatedEvent>, IHandle<PendingReleasesUpdatedEvent>
|
||||||
{
|
{
|
||||||
private readonly IQueueService _queueService;
|
private readonly IQueueService _queueService;
|
||||||
private readonly IPendingReleaseService _pendingReleaseService;
|
private readonly IPendingReleaseService _pendingReleaseService;
|
||||||
private readonly Debouncer _broadcastDebounce;
|
private readonly Debouncer _broadcastDebounce;
|
||||||
|
|
||||||
public QueueStatusModule(IBroadcastSignalRMessage broadcastSignalRMessage, IQueueService queueService, IPendingReleaseService pendingReleaseService)
|
public QueueStatusController(IBroadcastSignalRMessage broadcastSignalRMessage, IQueueService queueService, IPendingReleaseService pendingReleaseService)
|
||||||
: base(broadcastSignalRMessage, "queue/status")
|
: base(broadcastSignalRMessage)
|
||||||
{
|
{
|
||||||
_queueService = queueService;
|
_queueService = queueService;
|
||||||
_pendingReleaseService = pendingReleaseService;
|
_pendingReleaseService = pendingReleaseService;
|
||||||
|
|
||||||
_broadcastDebounce = new Debouncer(BroadcastChange, TimeSpan.FromSeconds(5));
|
_broadcastDebounce = new Debouncer(BroadcastChange, TimeSpan.FromSeconds(5));
|
||||||
|
|
||||||
Get("/", x => GetQueueStatusResponse());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private object GetQueueStatusResponse()
|
public override QueueStatusResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
return GetQueueStatus();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private QueueStatusResource GetQueueStatus()
|
[HttpGet]
|
||||||
|
public QueueStatusResource GetQueueStatus()
|
||||||
{
|
{
|
||||||
_broadcastDebounce.Pause();
|
_broadcastDebounce.Pause();
|
||||||
|
|
||||||
|
@ -62,11 +64,13 @@ namespace Lidarr.Api.V1.Queue
|
||||||
BroadcastResourceChange(ModelAction.Updated, GetQueueStatus());
|
BroadcastResourceChange(ModelAction.Updated, GetQueueStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(QueueUpdatedEvent message)
|
public void Handle(QueueUpdatedEvent message)
|
||||||
{
|
{
|
||||||
_broadcastDebounce.Execute();
|
_broadcastDebounce.Execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(PendingReleasesUpdatedEvent message)
|
public void Handle(PendingReleasesUpdatedEvent message)
|
||||||
{
|
{
|
||||||
_broadcastDebounce.Execute();
|
_broadcastDebounce.Execute();
|
|
@ -1,27 +1,25 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
using NzbDrone.Core.Validation.Paths;
|
using NzbDrone.Core.Validation.Paths;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.RemotePathMappings
|
namespace Lidarr.Api.V1.RemotePathMappings
|
||||||
{
|
{
|
||||||
public class RemotePathMappingModule : LidarrRestModule<RemotePathMappingResource>
|
[V1ApiController]
|
||||||
|
public class RemotePathMappingController : RestController<RemotePathMappingResource>
|
||||||
{
|
{
|
||||||
private readonly IRemotePathMappingService _remotePathMappingService;
|
private readonly IRemotePathMappingService _remotePathMappingService;
|
||||||
|
|
||||||
public RemotePathMappingModule(IRemotePathMappingService remotePathMappingService,
|
public RemotePathMappingController(IRemotePathMappingService remotePathMappingService,
|
||||||
PathExistsValidator pathExistsValidator,
|
PathExistsValidator pathExistsValidator,
|
||||||
MappedNetworkDriveValidator mappedNetworkDriveValidator)
|
MappedNetworkDriveValidator mappedNetworkDriveValidator)
|
||||||
{
|
{
|
||||||
_remotePathMappingService = remotePathMappingService;
|
_remotePathMappingService = remotePathMappingService;
|
||||||
|
|
||||||
GetResourceAll = GetMappings;
|
|
||||||
GetResourceById = GetMappingById;
|
|
||||||
CreateResource = CreateMapping;
|
|
||||||
DeleteResource = DeleteMapping;
|
|
||||||
UpdateResource = UpdateMapping;
|
|
||||||
|
|
||||||
SharedValidator.RuleFor(c => c.Host)
|
SharedValidator.RuleFor(c => c.Host)
|
||||||
.NotEmpty();
|
.NotEmpty();
|
||||||
|
|
||||||
|
@ -36,33 +34,37 @@ namespace Lidarr.Api.V1.RemotePathMappings
|
||||||
.SetValidator(pathExistsValidator);
|
.SetValidator(pathExistsValidator);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RemotePathMappingResource GetMappingById(int id)
|
public override RemotePathMappingResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
return _remotePathMappingService.Get(id).ToResource();
|
return _remotePathMappingService.Get(id).ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int CreateMapping(RemotePathMappingResource resource)
|
[RestPostById]
|
||||||
|
public ActionResult<RemotePathMappingResource> CreateMapping(RemotePathMappingResource resource)
|
||||||
{
|
{
|
||||||
var model = resource.ToModel();
|
var model = resource.ToModel();
|
||||||
|
|
||||||
return _remotePathMappingService.Add(model).Id;
|
return Created(_remotePathMappingService.Add(model).Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<RemotePathMappingResource> GetMappings()
|
[HttpGet]
|
||||||
|
public List<RemotePathMappingResource> GetMappings()
|
||||||
{
|
{
|
||||||
return _remotePathMappingService.All().ToResource();
|
return _remotePathMappingService.All().ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteMapping(int id)
|
[RestDeleteById]
|
||||||
|
public void DeleteMapping(int id)
|
||||||
{
|
{
|
||||||
_remotePathMappingService.Remove(id);
|
_remotePathMappingService.Remove(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateMapping(RemotePathMappingResource resource)
|
[RestPutById]
|
||||||
|
public ActionResult<RemotePathMappingResource> UpdateMapping(RemotePathMappingResource resource)
|
||||||
{
|
{
|
||||||
var mapping = resource.ToModel();
|
var mapping = resource.ToModel();
|
||||||
|
|
||||||
_remotePathMappingService.Update(mapping);
|
return Accepted(_remotePathMappingService.Update(mapping));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,6 +2,8 @@ using System.Collections.Generic;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.REST;
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.RootFolders;
|
using NzbDrone.Core.RootFolders;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
using NzbDrone.Core.Validation.Paths;
|
using NzbDrone.Core.Validation.Paths;
|
||||||
|
@ -9,11 +11,12 @@ using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.RootFolders
|
namespace Lidarr.Api.V1.RootFolders
|
||||||
{
|
{
|
||||||
public class RootFolderModule : LidarrRestModuleWithSignalR<RootFolderResource, RootFolder>
|
[V1ApiController]
|
||||||
|
public class RootFolderController : RestControllerWithSignalR<RootFolderResource, RootFolder>
|
||||||
{
|
{
|
||||||
private readonly IRootFolderService _rootFolderService;
|
private readonly IRootFolderService _rootFolderService;
|
||||||
|
|
||||||
public RootFolderModule(IRootFolderService rootFolderService,
|
public RootFolderController(IRootFolderService rootFolderService,
|
||||||
IBroadcastSignalRMessage signalRBroadcaster,
|
IBroadcastSignalRMessage signalRBroadcaster,
|
||||||
RootFolderValidator rootFolderValidator,
|
RootFolderValidator rootFolderValidator,
|
||||||
PathExistsValidator pathExistsValidator,
|
PathExistsValidator pathExistsValidator,
|
||||||
|
@ -27,12 +30,6 @@ namespace Lidarr.Api.V1.RootFolders
|
||||||
{
|
{
|
||||||
_rootFolderService = rootFolderService;
|
_rootFolderService = rootFolderService;
|
||||||
|
|
||||||
GetResourceAll = GetRootFolders;
|
|
||||||
GetResourceById = GetRootFolder;
|
|
||||||
CreateResource = CreateRootFolder;
|
|
||||||
UpdateResource = UpdateRootFolder;
|
|
||||||
DeleteResource = DeleteFolder;
|
|
||||||
|
|
||||||
SharedValidator.RuleFor(c => c.Path)
|
SharedValidator.RuleFor(c => c.Path)
|
||||||
.Cascade(CascadeMode.StopOnFirstFailure)
|
.Cascade(CascadeMode.StopOnFirstFailure)
|
||||||
.IsValidPath()
|
.IsValidPath()
|
||||||
|
@ -55,19 +52,21 @@ namespace Lidarr.Api.V1.RootFolders
|
||||||
.SetValidator(qualityProfileExistsValidator);
|
.SetValidator(qualityProfileExistsValidator);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RootFolderResource GetRootFolder(int id)
|
public override RootFolderResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
return _rootFolderService.Get(id).ToResource();
|
return _rootFolderService.Get(id).ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int CreateRootFolder(RootFolderResource rootFolderResource)
|
[RestPostById]
|
||||||
|
public ActionResult<RootFolderResource> CreateRootFolder(RootFolderResource rootFolderResource)
|
||||||
{
|
{
|
||||||
var model = rootFolderResource.ToModel();
|
var model = rootFolderResource.ToModel();
|
||||||
|
|
||||||
return _rootFolderService.Add(model).Id;
|
return Created(_rootFolderService.Add(model).Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateRootFolder(RootFolderResource rootFolderResource)
|
[RestPutById]
|
||||||
|
public ActionResult<RootFolderResource> UpdateRootFolder(RootFolderResource rootFolderResource)
|
||||||
{
|
{
|
||||||
var model = rootFolderResource.ToModel();
|
var model = rootFolderResource.ToModel();
|
||||||
|
|
||||||
|
@ -77,14 +76,18 @@ namespace Lidarr.Api.V1.RootFolders
|
||||||
}
|
}
|
||||||
|
|
||||||
_rootFolderService.Update(model);
|
_rootFolderService.Update(model);
|
||||||
|
|
||||||
|
return Accepted(model.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<RootFolderResource> GetRootFolders()
|
[HttpGet]
|
||||||
|
public List<RootFolderResource> GetRootFolders()
|
||||||
{
|
{
|
||||||
return _rootFolderService.AllWithSpaceStats().ToResource();
|
return _rootFolderService.AllWithSpaceStats().ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteFolder(int id)
|
[RestDeleteById]
|
||||||
|
public void DeleteFolder(int id)
|
||||||
{
|
{
|
||||||
_rootFolderService.Remove(id);
|
_rootFolderService.Remove(id);
|
||||||
}
|
}
|
|
@ -4,26 +4,26 @@ using System.Linq;
|
||||||
using Lidarr.Api.V1.Albums;
|
using Lidarr.Api.V1.Albums;
|
||||||
using Lidarr.Api.V1.Artist;
|
using Lidarr.Api.V1.Artist;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Nancy;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.MediaCover;
|
using NzbDrone.Core.MediaCover;
|
||||||
using NzbDrone.Core.MetadataSource;
|
using NzbDrone.Core.MetadataSource;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Search
|
namespace Lidarr.Api.V1.Search
|
||||||
{
|
{
|
||||||
public class SearchModule : LidarrRestModule<SearchResource>
|
[V1ApiController]
|
||||||
|
public class SearchController : Controller
|
||||||
{
|
{
|
||||||
private readonly ISearchForNewEntity _searchProxy;
|
private readonly ISearchForNewEntity _searchProxy;
|
||||||
|
|
||||||
public SearchModule(ISearchForNewEntity searchProxy)
|
public SearchController(ISearchForNewEntity searchProxy)
|
||||||
: base("/search")
|
|
||||||
{
|
{
|
||||||
_searchProxy = searchProxy;
|
_searchProxy = searchProxy;
|
||||||
Get("/", x => Search());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private object Search()
|
[HttpGet]
|
||||||
|
public object Search([FromQuery] string term)
|
||||||
{
|
{
|
||||||
var searchResults = _searchProxy.SearchForNewEntity((string)Request.Query.term);
|
var searchResults = _searchProxy.SearchForNewEntity(term);
|
||||||
return MapToResource(searchResults).ToList();
|
return MapToResource(searchResults).ToList();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.REST;
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common.Crypto;
|
using NzbDrone.Common.Crypto;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
|
@ -11,7 +13,8 @@ using NzbDrone.Core.Backup;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.System.Backup
|
namespace Lidarr.Api.V1.System.Backup
|
||||||
{
|
{
|
||||||
public class BackupModule : LidarrRestModule<BackupResource>
|
[V1ApiController("system/backup")]
|
||||||
|
public class BackupController : Controller
|
||||||
{
|
{
|
||||||
private readonly IBackupService _backupService;
|
private readonly IBackupService _backupService;
|
||||||
private readonly IAppFolderInfo _appFolderInfo;
|
private readonly IAppFolderInfo _appFolderInfo;
|
||||||
|
@ -19,21 +22,16 @@ namespace Lidarr.Api.V1.System.Backup
|
||||||
|
|
||||||
private static readonly List<string> ValidExtensions = new List<string> { ".zip", ".db", ".xml" };
|
private static readonly List<string> ValidExtensions = new List<string> { ".zip", ".db", ".xml" };
|
||||||
|
|
||||||
public BackupModule(IBackupService backupService,
|
public BackupController(IBackupService backupService,
|
||||||
IAppFolderInfo appFolderInfo,
|
IAppFolderInfo appFolderInfo,
|
||||||
IDiskProvider diskProvider)
|
IDiskProvider diskProvider)
|
||||||
: base("system/backup")
|
|
||||||
{
|
{
|
||||||
_backupService = backupService;
|
_backupService = backupService;
|
||||||
_appFolderInfo = appFolderInfo;
|
_appFolderInfo = appFolderInfo;
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
GetResourceAll = GetBackupFiles;
|
|
||||||
DeleteResource = DeleteBackup;
|
|
||||||
|
|
||||||
Post(@"/restore/(?<id>[\d]{1,10})", x => Restore((int)x.Id));
|
|
||||||
Post("/restore/upload", x => UploadAndRestore());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
public List<BackupResource> GetBackupFiles()
|
public List<BackupResource> GetBackupFiles()
|
||||||
{
|
{
|
||||||
var backups = _backupService.GetBackups();
|
var backups = _backupService.GetBackups();
|
||||||
|
@ -50,7 +48,8 @@ namespace Lidarr.Api.V1.System.Backup
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteBackup(int id)
|
[RestDeleteById]
|
||||||
|
public void DeleteBackup(int id)
|
||||||
{
|
{
|
||||||
var backup = GetBackup(id);
|
var backup = GetBackup(id);
|
||||||
var path = GetBackupPath(backup);
|
var path = GetBackupPath(backup);
|
||||||
|
@ -63,6 +62,7 @@ namespace Lidarr.Api.V1.System.Backup
|
||||||
_diskProvider.DeleteFile(path);
|
_diskProvider.DeleteFile(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost("restore/{id:int}")]
|
||||||
public object Restore(int id)
|
public object Restore(int id)
|
||||||
{
|
{
|
||||||
var backup = GetBackup(id);
|
var backup = GetBackup(id);
|
||||||
|
@ -82,9 +82,10 @@ namespace Lidarr.Api.V1.System.Backup
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost("restore/upload")]
|
||||||
public object UploadAndRestore()
|
public object UploadAndRestore()
|
||||||
{
|
{
|
||||||
var files = Context.Request.Files.ToList();
|
var files = Request.Form.Files;
|
||||||
|
|
||||||
if (files.Empty())
|
if (files.Empty())
|
||||||
{
|
{
|
||||||
|
@ -92,7 +93,7 @@ namespace Lidarr.Api.V1.System.Backup
|
||||||
}
|
}
|
||||||
|
|
||||||
var file = files.First();
|
var file = files.First();
|
||||||
var extension = Path.GetExtension(file.Name);
|
var extension = Path.GetExtension(file.FileName);
|
||||||
|
|
||||||
if (!ValidExtensions.Contains(extension))
|
if (!ValidExtensions.Contains(extension))
|
||||||
{
|
{
|
||||||
|
@ -101,7 +102,7 @@ namespace Lidarr.Api.V1.System.Backup
|
||||||
|
|
||||||
var path = Path.Combine(_appFolderInfo.TempFolder, $"lidarr_backup_restore{extension}");
|
var path = Path.Combine(_appFolderInfo.TempFolder, $"lidarr_backup_restore{extension}");
|
||||||
|
|
||||||
_diskProvider.SaveStream(file.Value, path);
|
_diskProvider.SaveStream(file.OpenReadStream(), path);
|
||||||
_backupService.Restore(path);
|
_backupService.Restore(path);
|
||||||
|
|
||||||
// Cleanup restored file
|
// Cleanup restored file
|
|
@ -1,5 +1,10 @@
|
||||||
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Nancy.Routing;
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.Validation;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
|
@ -8,45 +13,48 @@ using NzbDrone.Core.Lifecycle;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.System
|
namespace Lidarr.Api.V1.System
|
||||||
{
|
{
|
||||||
public class SystemModule : LidarrV1Module
|
[V1ApiController]
|
||||||
|
public class SystemController : Controller
|
||||||
{
|
{
|
||||||
private readonly IAppFolderInfo _appFolderInfo;
|
private readonly IAppFolderInfo _appFolderInfo;
|
||||||
private readonly IRuntimeInfo _runtimeInfo;
|
private readonly IRuntimeInfo _runtimeInfo;
|
||||||
private readonly IPlatformInfo _platformInfo;
|
private readonly IPlatformInfo _platformInfo;
|
||||||
private readonly IOsInfo _osInfo;
|
private readonly IOsInfo _osInfo;
|
||||||
private readonly IRouteCacheProvider _routeCacheProvider;
|
|
||||||
private readonly IConfigFileProvider _configFileProvider;
|
private readonly IConfigFileProvider _configFileProvider;
|
||||||
private readonly IMainDatabase _database;
|
private readonly IMainDatabase _database;
|
||||||
private readonly ILifecycleService _lifecycleService;
|
private readonly ILifecycleService _lifecycleService;
|
||||||
private readonly IDeploymentInfoProvider _deploymentInfoProvider;
|
private readonly IDeploymentInfoProvider _deploymentInfoProvider;
|
||||||
|
private readonly EndpointDataSource _endpointData;
|
||||||
|
private readonly DfaGraphWriter _graphWriter;
|
||||||
|
private readonly DuplicateEndpointDetector _detector;
|
||||||
|
|
||||||
public SystemModule(IAppFolderInfo appFolderInfo,
|
public SystemController(IAppFolderInfo appFolderInfo,
|
||||||
IRuntimeInfo runtimeInfo,
|
IRuntimeInfo runtimeInfo,
|
||||||
IPlatformInfo platformInfo,
|
IPlatformInfo platformInfo,
|
||||||
IOsInfo osInfo,
|
IOsInfo osInfo,
|
||||||
IRouteCacheProvider routeCacheProvider,
|
|
||||||
IConfigFileProvider configFileProvider,
|
IConfigFileProvider configFileProvider,
|
||||||
IMainDatabase database,
|
IMainDatabase database,
|
||||||
ILifecycleService lifecycleService,
|
ILifecycleService lifecycleService,
|
||||||
IDeploymentInfoProvider deploymentInfoProvider)
|
IDeploymentInfoProvider deploymentInfoProvider,
|
||||||
: base("system")
|
EndpointDataSource endpoints,
|
||||||
|
DfaGraphWriter graphWriter,
|
||||||
|
DuplicateEndpointDetector detector)
|
||||||
{
|
{
|
||||||
_appFolderInfo = appFolderInfo;
|
_appFolderInfo = appFolderInfo;
|
||||||
_runtimeInfo = runtimeInfo;
|
_runtimeInfo = runtimeInfo;
|
||||||
_platformInfo = platformInfo;
|
_platformInfo = platformInfo;
|
||||||
_osInfo = osInfo;
|
_osInfo = osInfo;
|
||||||
_routeCacheProvider = routeCacheProvider;
|
|
||||||
_configFileProvider = configFileProvider;
|
_configFileProvider = configFileProvider;
|
||||||
_database = database;
|
_database = database;
|
||||||
_lifecycleService = lifecycleService;
|
_lifecycleService = lifecycleService;
|
||||||
_deploymentInfoProvider = deploymentInfoProvider;
|
_deploymentInfoProvider = deploymentInfoProvider;
|
||||||
Get("/status", x => GetStatus());
|
_endpointData = endpoints;
|
||||||
Get("/routes", x => GetRoutes());
|
_graphWriter = graphWriter;
|
||||||
Post("/shutdown", x => Shutdown());
|
_detector = detector;
|
||||||
Post("/restart", x => Restart());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private object GetStatus()
|
[HttpGet("status")]
|
||||||
|
public object GetStatus()
|
||||||
{
|
{
|
||||||
return new
|
return new
|
||||||
{
|
{
|
||||||
|
@ -81,18 +89,32 @@ namespace Lidarr.Api.V1.System
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private object GetRoutes()
|
[HttpGet("routes")]
|
||||||
|
public IActionResult GetRoutes()
|
||||||
{
|
{
|
||||||
return _routeCacheProvider.GetCache().Values;
|
using (var sw = new StringWriter())
|
||||||
|
{
|
||||||
|
_graphWriter.Write(_endpointData, sw);
|
||||||
|
var graph = sw.ToString();
|
||||||
|
return Content(graph, "text/plain");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private object Shutdown()
|
[HttpGet("routes/duplicate")]
|
||||||
|
public object DuplicateRoutes()
|
||||||
|
{
|
||||||
|
return _detector.GetDuplicateEndpoints(_endpointData);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("shutdown")]
|
||||||
|
public object Shutdown()
|
||||||
{
|
{
|
||||||
Task.Factory.StartNew(() => _lifecycleService.Shutdown());
|
Task.Factory.StartNew(() => _lifecycleService.Shutdown());
|
||||||
return new { ShuttingDown = true };
|
return new { ShuttingDown = true };
|
||||||
}
|
}
|
||||||
|
|
||||||
private object Restart()
|
[HttpPost("restart")]
|
||||||
|
public object Restart()
|
||||||
{
|
{
|
||||||
Task.Factory.StartNew(() => _lifecycleService.Restart());
|
Task.Factory.StartNew(() => _lifecycleService.Restart());
|
||||||
return new { Restarting = true };
|
return new { Restarting = true };
|
|
@ -1,6 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
using NzbDrone.Core.Datastore.Events;
|
||||||
using NzbDrone.Core.Jobs;
|
using NzbDrone.Core.Jobs;
|
||||||
|
@ -9,19 +11,19 @@ using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.System.Tasks
|
namespace Lidarr.Api.V1.System.Tasks
|
||||||
{
|
{
|
||||||
public class TaskModule : LidarrRestModuleWithSignalR<TaskResource, ScheduledTask>, IHandle<CommandExecutedEvent>
|
[V1ApiController("system/task")]
|
||||||
|
public class TaskController : RestControllerWithSignalR<TaskResource, ScheduledTask>, IHandle<CommandExecutedEvent>
|
||||||
{
|
{
|
||||||
private readonly ITaskManager _taskManager;
|
private readonly ITaskManager _taskManager;
|
||||||
|
|
||||||
public TaskModule(ITaskManager taskManager, IBroadcastSignalRMessage broadcastSignalRMessage)
|
public TaskController(ITaskManager taskManager, IBroadcastSignalRMessage broadcastSignalRMessage)
|
||||||
: base(broadcastSignalRMessage, "system/task")
|
: base(broadcastSignalRMessage)
|
||||||
{
|
{
|
||||||
_taskManager = taskManager;
|
_taskManager = taskManager;
|
||||||
GetResourceAll = GetAll;
|
|
||||||
GetResourceById = GetTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TaskResource> GetAll()
|
[HttpGet]
|
||||||
|
public List<TaskResource> GetAll()
|
||||||
{
|
{
|
||||||
return _taskManager.GetAll()
|
return _taskManager.GetAll()
|
||||||
.Select(ConvertToResource)
|
.Select(ConvertToResource)
|
||||||
|
@ -29,7 +31,7 @@ namespace Lidarr.Api.V1.System.Tasks
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskResource GetTask(int id)
|
public override TaskResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
var task = _taskManager.GetAll()
|
var task = _taskManager.GetAll()
|
||||||
.SingleOrDefault(t => t.Id == id);
|
.SingleOrDefault(t => t.Id == id);
|
||||||
|
@ -58,6 +60,7 @@ namespace Lidarr.Api.V1.System.Tasks
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(CommandExecutedEvent message)
|
public void Handle(CommandExecutedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Sync);
|
BroadcastResourceChange(ModelAction.Sync);
|
|
@ -1,5 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
using NzbDrone.Core.Datastore.Events;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Tags;
|
using NzbDrone.Core.Tags;
|
||||||
|
@ -7,48 +10,49 @@ using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Tags
|
namespace Lidarr.Api.V1.Tags
|
||||||
{
|
{
|
||||||
public class TagModule : LidarrRestModuleWithSignalR<TagResource, Tag>, IHandle<TagsUpdatedEvent>
|
[V1ApiController]
|
||||||
|
public class TagController : RestControllerWithSignalR<TagResource, Tag>, IHandle<TagsUpdatedEvent>
|
||||||
{
|
{
|
||||||
private readonly ITagService _tagService;
|
private readonly ITagService _tagService;
|
||||||
|
|
||||||
public TagModule(IBroadcastSignalRMessage signalRBroadcaster,
|
public TagController(IBroadcastSignalRMessage signalRBroadcaster,
|
||||||
ITagService tagService)
|
ITagService tagService)
|
||||||
: base(signalRBroadcaster)
|
: base(signalRBroadcaster)
|
||||||
{
|
{
|
||||||
_tagService = tagService;
|
_tagService = tagService;
|
||||||
|
|
||||||
GetResourceById = GetTag;
|
|
||||||
GetResourceAll = GetAll;
|
|
||||||
CreateResource = Create;
|
|
||||||
UpdateResource = Update;
|
|
||||||
DeleteResource = DeleteTag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TagResource GetTag(int id)
|
public override TagResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
return _tagService.GetTag(id).ToResource();
|
return _tagService.GetTag(id).ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TagResource> GetAll()
|
[HttpGet]
|
||||||
|
public List<TagResource> GetAll()
|
||||||
{
|
{
|
||||||
return _tagService.All().ToResource();
|
return _tagService.All().ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int Create(TagResource resource)
|
[RestPostById]
|
||||||
|
public ActionResult<TagResource> Create(TagResource resource)
|
||||||
{
|
{
|
||||||
return _tagService.Add(resource.ToModel()).Id;
|
return Created(_tagService.Add(resource.ToModel()).Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Update(TagResource resource)
|
[RestPutById]
|
||||||
|
public ActionResult<TagResource> Update(TagResource resource)
|
||||||
{
|
{
|
||||||
_tagService.Update(resource.ToModel());
|
_tagService.Update(resource.ToModel());
|
||||||
|
return Accepted(resource.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteTag(int id)
|
[RestDeleteById]
|
||||||
|
public void DeleteTag(int id)
|
||||||
{
|
{
|
||||||
_tagService.Delete(id);
|
_tagService.Delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(TagsUpdatedEvent message)
|
public void Handle(TagsUpdatedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Sync);
|
BroadcastResourceChange(ModelAction.Sync);
|
|
@ -1,28 +1,28 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Tags;
|
using NzbDrone.Core.Tags;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Tags
|
namespace Lidarr.Api.V1.Tags
|
||||||
{
|
{
|
||||||
public class TagDetailsModule : LidarrRestModule<TagDetailsResource>
|
[V1ApiController("tag/detail")]
|
||||||
|
public class TagDetailsController : RestController<TagDetailsResource>
|
||||||
{
|
{
|
||||||
private readonly ITagService _tagService;
|
private readonly ITagService _tagService;
|
||||||
|
|
||||||
public TagDetailsModule(ITagService tagService)
|
public TagDetailsController(ITagService tagService)
|
||||||
: base("/tag/detail")
|
|
||||||
{
|
{
|
||||||
_tagService = tagService;
|
_tagService = tagService;
|
||||||
|
|
||||||
GetResourceById = GetTagDetails;
|
|
||||||
GetResourceAll = GetAll;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TagDetailsResource GetTagDetails(int id)
|
public override TagDetailsResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
return _tagService.Details(id).ToResource();
|
return _tagService.Details(id).ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TagDetailsResource> GetAll()
|
[HttpGet]
|
||||||
|
public List<TagDetailsResource> GetAll()
|
||||||
{
|
{
|
||||||
var tags = _tagService.Details().ToResource();
|
var tags = _tagService.Details().ToResource();
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.Extensions;
|
using Lidarr.Http.REST;
|
||||||
using Nancy;
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
using NzbDrone.Core.Datastore.Events;
|
||||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||||
using NzbDrone.Core.Exceptions;
|
using NzbDrone.Core.Exceptions;
|
||||||
|
@ -12,11 +12,13 @@ using NzbDrone.Core.MediaFiles.Events;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
using NzbDrone.SignalR;
|
using NzbDrone.SignalR;
|
||||||
|
using BadRequestException = Lidarr.Http.REST.BadRequestException;
|
||||||
using HttpStatusCode = System.Net.HttpStatusCode;
|
using HttpStatusCode = System.Net.HttpStatusCode;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.TrackFiles
|
namespace Lidarr.Api.V1.TrackFiles
|
||||||
{
|
{
|
||||||
public class TrackFileModule : LidarrRestModuleWithSignalR<TrackFileResource, TrackFile>,
|
[V1ApiController]
|
||||||
|
public class TrackFileController : RestControllerWithSignalR<TrackFileResource, TrackFile>,
|
||||||
IHandle<TrackFileAddedEvent>,
|
IHandle<TrackFileAddedEvent>,
|
||||||
IHandle<TrackFileDeletedEvent>
|
IHandle<TrackFileDeletedEvent>
|
||||||
{
|
{
|
||||||
|
@ -27,7 +29,7 @@ namespace Lidarr.Api.V1.TrackFiles
|
||||||
private readonly IAlbumService _albumService;
|
private readonly IAlbumService _albumService;
|
||||||
private readonly IUpgradableSpecification _upgradableSpecification;
|
private readonly IUpgradableSpecification _upgradableSpecification;
|
||||||
|
|
||||||
public TrackFileModule(IBroadcastSignalRMessage signalRBroadcaster,
|
public TrackFileController(IBroadcastSignalRMessage signalRBroadcaster,
|
||||||
IMediaFileService mediaFileService,
|
IMediaFileService mediaFileService,
|
||||||
IDeleteMediaFiles mediaFileDeletionService,
|
IDeleteMediaFiles mediaFileDeletionService,
|
||||||
IAudioTagService audioTagService,
|
IAudioTagService audioTagService,
|
||||||
|
@ -42,14 +44,6 @@ namespace Lidarr.Api.V1.TrackFiles
|
||||||
_artistService = artistService;
|
_artistService = artistService;
|
||||||
_albumService = albumService;
|
_albumService = albumService;
|
||||||
_upgradableSpecification = upgradableSpecification;
|
_upgradableSpecification = upgradableSpecification;
|
||||||
|
|
||||||
GetResourceById = GetTrackFile;
|
|
||||||
GetResourceAll = GetTrackFiles;
|
|
||||||
UpdateResource = SetQuality;
|
|
||||||
DeleteResource = DeleteTrackFile;
|
|
||||||
|
|
||||||
Put("/editor", trackFiles => SetQuality());
|
|
||||||
Delete("/bulk", trackFiles => DeleteTrackFiles());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TrackFileResource MapToResource(TrackFile trackFile)
|
private TrackFileResource MapToResource(TrackFile trackFile)
|
||||||
|
@ -64,47 +58,36 @@ namespace Lidarr.Api.V1.TrackFiles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TrackFileResource GetTrackFile(int id)
|
public override TrackFileResource GetResourceById(int id)
|
||||||
{
|
{
|
||||||
var resource = MapToResource(_mediaFileService.Get(id));
|
var resource = MapToResource(_mediaFileService.Get(id));
|
||||||
resource.AudioTags = _audioTagService.ReadTags(resource.Path);
|
resource.AudioTags = _audioTagService.ReadTags(resource.Path);
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TrackFileResource> GetTrackFiles()
|
[HttpGet]
|
||||||
|
public List<TrackFileResource> GetTrackFiles(int? artistId, [FromQuery] List<int> trackFileIds, [FromQuery(Name = "albumId")] List<int> albumIds, bool? unmapped)
|
||||||
{
|
{
|
||||||
var artistIdQuery = Request.Query.ArtistId;
|
if (!artistId.HasValue && !trackFileIds.Any() && !albumIds.Any() && !unmapped.HasValue)
|
||||||
var trackFileIdsQuery = Request.Query.TrackFileIds;
|
|
||||||
var albumIdQuery = Request.Query.AlbumId;
|
|
||||||
var unmappedQuery = Request.Query.Unmapped;
|
|
||||||
|
|
||||||
if (!artistIdQuery.HasValue && !trackFileIdsQuery.HasValue && !albumIdQuery.HasValue && !unmappedQuery.HasValue)
|
|
||||||
{
|
{
|
||||||
throw new Lidarr.Http.REST.BadRequestException("artistId, albumId, trackFileIds or unmapped must be provided");
|
throw new BadRequestException("artistId, albumId, trackFileIds or unmapped must be provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unmappedQuery.HasValue && Convert.ToBoolean(unmappedQuery.Value))
|
if (unmapped.HasValue && unmapped.Value)
|
||||||
{
|
{
|
||||||
var files = _mediaFileService.GetUnmappedFiles();
|
var files = _mediaFileService.GetUnmappedFiles();
|
||||||
return files.ConvertAll(f => MapToResource(f));
|
return files.ConvertAll(f => MapToResource(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (artistIdQuery.HasValue && !albumIdQuery.HasValue)
|
if (artistId.HasValue && !albumIds.Any())
|
||||||
{
|
{
|
||||||
int artistId = Convert.ToInt32(artistIdQuery.Value);
|
var artist = _artistService.GetArtist(artistId.Value);
|
||||||
var artist = _artistService.GetArtist(artistId);
|
|
||||||
|
|
||||||
return _mediaFileService.GetFilesByArtist(artistId).ConvertAll(f => f.ToResource(artist, _upgradableSpecification));
|
return _mediaFileService.GetFilesByArtist(artistId.Value).ConvertAll(f => f.ToResource(artist, _upgradableSpecification));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (albumIdQuery.HasValue)
|
if (albumIds.Any())
|
||||||
{
|
{
|
||||||
string albumIdValue = albumIdQuery.Value.ToString();
|
|
||||||
|
|
||||||
var albumIds = albumIdValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Select(e => Convert.ToInt32(e))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var result = new List<TrackFileResource>();
|
var result = new List<TrackFileResource>();
|
||||||
foreach (var albumId in albumIds)
|
foreach (var albumId in albumIds)
|
||||||
{
|
{
|
||||||
|
@ -117,28 +100,24 @@ namespace Lidarr.Api.V1.TrackFiles
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string trackFileIdsValue = trackFileIdsQuery.Value.ToString();
|
|
||||||
|
|
||||||
var trackFileIds = trackFileIdsValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Select(e => Convert.ToInt32(e))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
// trackfiles will come back with the artist already populated
|
// trackfiles will come back with the artist already populated
|
||||||
var trackFiles = _mediaFileService.Get(trackFileIds);
|
var trackFiles = _mediaFileService.Get(trackFileIds);
|
||||||
return trackFiles.ConvertAll(e => MapToResource(e));
|
return trackFiles.ConvertAll(e => MapToResource(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetQuality(TrackFileResource trackFileResource)
|
[RestPutById]
|
||||||
|
public ActionResult<TrackFileResource> SetQuality([FromBody] TrackFileResource trackFileResource)
|
||||||
{
|
{
|
||||||
var trackFile = _mediaFileService.Get(trackFileResource.Id);
|
var trackFile = _mediaFileService.Get(trackFileResource.Id);
|
||||||
trackFile.Quality = trackFileResource.Quality;
|
trackFile.Quality = trackFileResource.Quality;
|
||||||
_mediaFileService.Update(trackFile);
|
_mediaFileService.Update(trackFile);
|
||||||
|
return Accepted(trackFile.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private object SetQuality()
|
[HttpPut("editor")]
|
||||||
|
public IActionResult SetQuality([FromBody] TrackFileListResource resource)
|
||||||
{
|
{
|
||||||
var resource = Request.Body.FromJson<TrackFileListResource>();
|
|
||||||
var trackFiles = _mediaFileService.Get(resource.TrackFileIds);
|
var trackFiles = _mediaFileService.Get(resource.TrackFileIds);
|
||||||
|
|
||||||
foreach (var trackFile in trackFiles)
|
foreach (var trackFile in trackFiles)
|
||||||
|
@ -151,11 +130,11 @@ namespace Lidarr.Api.V1.TrackFiles
|
||||||
|
|
||||||
_mediaFileService.Update(trackFiles);
|
_mediaFileService.Update(trackFiles);
|
||||||
|
|
||||||
return ResponseWithCode(trackFiles.ConvertAll(f => f.ToResource(trackFiles.First().Artist.Value, _upgradableSpecification)),
|
return Accepted(trackFiles.ConvertAll(f => f.ToResource(trackFiles.First().Artist.Value, _upgradableSpecification)));
|
||||||
Nancy.HttpStatusCode.Accepted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteTrackFile(int id)
|
[RestDeleteById]
|
||||||
|
public void DeleteTrackFile(int id)
|
||||||
{
|
{
|
||||||
var trackFile = _mediaFileService.Get(id);
|
var trackFile = _mediaFileService.Get(id);
|
||||||
|
|
||||||
|
@ -174,9 +153,9 @@ namespace Lidarr.Api.V1.TrackFiles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private object DeleteTrackFiles()
|
[HttpDelete("bulk")]
|
||||||
|
public IActionResult DeleteTrackFiles([FromBody] TrackFileListResource resource)
|
||||||
{
|
{
|
||||||
var resource = Request.Body.FromJson<TrackFileListResource>();
|
|
||||||
var trackFiles = _mediaFileService.Get(resource.TrackFileIds);
|
var trackFiles = _mediaFileService.Get(resource.TrackFileIds);
|
||||||
var artist = trackFiles.First().Artist.Value;
|
var artist = trackFiles.First().Artist.Value;
|
||||||
|
|
||||||
|
@ -185,14 +164,16 @@ namespace Lidarr.Api.V1.TrackFiles
|
||||||
_mediaFileDeletionService.DeleteTrackFile(artist, trackFile);
|
_mediaFileDeletionService.DeleteTrackFile(artist, trackFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new object();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(TrackFileAddedEvent message)
|
public void Handle(TrackFileAddedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Updated, MapToResource(message.TrackFile));
|
BroadcastResourceChange(ModelAction.Updated, MapToResource(message.TrackFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(TrackFileDeletedEvent message)
|
public void Handle(TrackFileDeletedEvent message)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Deleted, MapToResource(message.TrackFile));
|
BroadcastResourceChange(ModelAction.Deleted, MapToResource(message.TrackFile));
|
29
src/Lidarr.Api.V1/Tracks/RenameTrackController.cs
Normal file
29
src/Lidarr.Api.V1/Tracks/RenameTrackController.cs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Lidarr.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
|
||||||
|
namespace Lidarr.Api.V1.Tracks
|
||||||
|
{
|
||||||
|
[V1ApiController("rename")]
|
||||||
|
public class RenameTrackController : Controller
|
||||||
|
{
|
||||||
|
private readonly IRenameTrackFileService _renameTrackFileService;
|
||||||
|
|
||||||
|
public RenameTrackController(IRenameTrackFileService renameTrackFileService)
|
||||||
|
{
|
||||||
|
_renameTrackFileService = renameTrackFileService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public List<RenameTrackResource> GetTracks(int artistId, int? albumId)
|
||||||
|
{
|
||||||
|
if (albumId.HasValue)
|
||||||
|
{
|
||||||
|
return _renameTrackFileService.GetRenamePreviews(artistId, albumId.Value).ToResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _renameTrackFileService.GetRenamePreviews(artistId).ToResource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,42 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using Lidarr.Http;
|
|
||||||
using Lidarr.Http.REST;
|
|
||||||
using NzbDrone.Core.MediaFiles;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Tracks
|
|
||||||
{
|
|
||||||
public class RenameTrackModule : LidarrRestModule<RenameTrackResource>
|
|
||||||
{
|
|
||||||
private readonly IRenameTrackFileService _renameTrackFileService;
|
|
||||||
|
|
||||||
public RenameTrackModule(IRenameTrackFileService renameTrackFileService)
|
|
||||||
: base("rename")
|
|
||||||
{
|
|
||||||
_renameTrackFileService = renameTrackFileService;
|
|
||||||
|
|
||||||
GetResourceAll = GetTracks;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<RenameTrackResource> GetTracks()
|
|
||||||
{
|
|
||||||
int artistId;
|
|
||||||
|
|
||||||
if (Request.Query.ArtistId.HasValue)
|
|
||||||
{
|
|
||||||
artistId = (int)Request.Query.ArtistId;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new BadRequestException("artistId is missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Request.Query.albumId.HasValue)
|
|
||||||
{
|
|
||||||
var albumId = (int)Request.Query.albumId;
|
|
||||||
return _renameTrackFileService.GetRenamePreviews(artistId, albumId).ToResource();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _renameTrackFileService.GetRenamePreviews(artistId).ToResource();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
30
src/Lidarr.Api.V1/Tracks/RetagTrackController.cs
Normal file
30
src/Lidarr.Api.V1/Tracks/RetagTrackController.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Lidarr.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
|
||||||
|
namespace Lidarr.Api.V1.Tracks
|
||||||
|
{
|
||||||
|
[V1ApiController("retag")]
|
||||||
|
public class RetagTrackController : Controller
|
||||||
|
{
|
||||||
|
private readonly IAudioTagService _audioTagService;
|
||||||
|
|
||||||
|
public RetagTrackController(IAudioTagService audioTagService)
|
||||||
|
{
|
||||||
|
_audioTagService = audioTagService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public List<RetagTrackResource> GetTracks(int artistId, int? albumId)
|
||||||
|
{
|
||||||
|
if (albumId.HasValue)
|
||||||
|
{
|
||||||
|
return _audioTagService.GetRetagPreviewsByAlbum(albumId.Value).Where(x => x.Changes.Any()).ToResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _audioTagService.GetRetagPreviewsByArtist(artistId).Where(x => x.Changes.Any()).ToResource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,39 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Lidarr.Http;
|
|
||||||
using Lidarr.Http.REST;
|
|
||||||
using NzbDrone.Core.MediaFiles;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Tracks
|
|
||||||
{
|
|
||||||
public class RetagTrackModule : LidarrRestModule<RetagTrackResource>
|
|
||||||
{
|
|
||||||
private readonly IAudioTagService _audioTagService;
|
|
||||||
|
|
||||||
public RetagTrackModule(IAudioTagService audioTagService)
|
|
||||||
: base("retag")
|
|
||||||
{
|
|
||||||
_audioTagService = audioTagService;
|
|
||||||
|
|
||||||
GetResourceAll = GetTracks;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<RetagTrackResource> GetTracks()
|
|
||||||
{
|
|
||||||
if (Request.Query.albumId.HasValue)
|
|
||||||
{
|
|
||||||
var albumId = (int)Request.Query.albumId;
|
|
||||||
return _audioTagService.GetRetagPreviewsByAlbum(albumId).Where(x => x.Changes.Any()).ToResource();
|
|
||||||
}
|
|
||||||
else if (Request.Query.ArtistId.HasValue)
|
|
||||||
{
|
|
||||||
var artistId = (int)Request.Query.ArtistId;
|
|
||||||
return _audioTagService.GetRetagPreviewsByArtist(artistId).Where(x => x.Changes.Any()).ToResource();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new BadRequestException("One of artistId or albumId must be specified");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
52
src/Lidarr.Api.V1/Tracks/TrackController.cs
Normal file
52
src/Lidarr.Api.V1/Tracks/TrackController.cs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Lidarr.Http;
|
||||||
|
using Lidarr.Http.REST;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
using NzbDrone.SignalR;
|
||||||
|
|
||||||
|
namespace Lidarr.Api.V1.Tracks
|
||||||
|
{
|
||||||
|
[V1ApiController]
|
||||||
|
public class TrackController : TrackControllerWithSignalR
|
||||||
|
{
|
||||||
|
public TrackController(IArtistService artistService,
|
||||||
|
ITrackService trackService,
|
||||||
|
IUpgradableSpecification upgradableSpecification,
|
||||||
|
IBroadcastSignalRMessage signalRBroadcaster)
|
||||||
|
: base(trackService, artistService, upgradableSpecification, signalRBroadcaster)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public List<TrackResource> GetTracks([FromQuery]int? artistId,
|
||||||
|
[FromQuery]int? albumId,
|
||||||
|
[FromQuery]int? albumReleaseId,
|
||||||
|
[FromQuery]List<int> trackIds)
|
||||||
|
{
|
||||||
|
if (!artistId.HasValue && !trackIds.Any() && !albumId.HasValue && !albumReleaseId.HasValue)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("One of artistId, albumId, albumReleaseId or trackIds must be provided");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (artistId.HasValue && !albumId.HasValue)
|
||||||
|
{
|
||||||
|
return MapToResource(_trackService.GetTracksByArtist(artistId.Value), false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (albumReleaseId.HasValue)
|
||||||
|
{
|
||||||
|
return MapToResource(_trackService.GetTracksByRelease(albumReleaseId.Value), false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (albumId.HasValue)
|
||||||
|
{
|
||||||
|
return MapToResource(_trackService.GetTracksByAlbum(albumId.Value), false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return MapToResource(_trackService.GetTracks(trackIds), false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Lidarr.Api.V1.Artist;
|
using Lidarr.Api.V1.Artist;
|
||||||
using Lidarr.Api.V1.TrackFiles;
|
using Lidarr.Api.V1.TrackFiles;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http.REST;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
using NzbDrone.Core.Datastore.Events;
|
||||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||||
using NzbDrone.Core.MediaFiles.Events;
|
using NzbDrone.Core.MediaFiles.Events;
|
||||||
|
@ -11,7 +12,7 @@ using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Tracks
|
namespace Lidarr.Api.V1.Tracks
|
||||||
{
|
{
|
||||||
public abstract class TrackModuleWithSignalR : LidarrRestModuleWithSignalR<TrackResource, Track>,
|
public abstract class TrackControllerWithSignalR : RestControllerWithSignalR<TrackResource, Track>,
|
||||||
IHandle<TrackImportedEvent>,
|
IHandle<TrackImportedEvent>,
|
||||||
IHandle<TrackFileDeletedEvent>
|
IHandle<TrackFileDeletedEvent>
|
||||||
{
|
{
|
||||||
|
@ -19,7 +20,7 @@ namespace Lidarr.Api.V1.Tracks
|
||||||
protected readonly IArtistService _artistService;
|
protected readonly IArtistService _artistService;
|
||||||
protected readonly IUpgradableSpecification _upgradableSpecification;
|
protected readonly IUpgradableSpecification _upgradableSpecification;
|
||||||
|
|
||||||
protected TrackModuleWithSignalR(ITrackService trackService,
|
protected TrackControllerWithSignalR(ITrackService trackService,
|
||||||
IArtistService artistService,
|
IArtistService artistService,
|
||||||
IUpgradableSpecification upgradableSpecification,
|
IUpgradableSpecification upgradableSpecification,
|
||||||
IBroadcastSignalRMessage signalRBroadcaster)
|
IBroadcastSignalRMessage signalRBroadcaster)
|
||||||
|
@ -28,25 +29,9 @@ namespace Lidarr.Api.V1.Tracks
|
||||||
_trackService = trackService;
|
_trackService = trackService;
|
||||||
_artistService = artistService;
|
_artistService = artistService;
|
||||||
_upgradableSpecification = upgradableSpecification;
|
_upgradableSpecification = upgradableSpecification;
|
||||||
|
|
||||||
GetResourceById = GetTrack;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TrackModuleWithSignalR(ITrackService trackService,
|
public override TrackResource GetResourceById(int id)
|
||||||
IArtistService artistService,
|
|
||||||
IUpgradableSpecification upgradableSpecification,
|
|
||||||
IBroadcastSignalRMessage signalRBroadcaster,
|
|
||||||
string resource)
|
|
||||||
: base(signalRBroadcaster, resource)
|
|
||||||
{
|
|
||||||
_trackService = trackService;
|
|
||||||
_artistService = artistService;
|
|
||||||
_upgradableSpecification = upgradableSpecification;
|
|
||||||
|
|
||||||
GetResourceById = GetTrack;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected TrackResource GetTrack(int id)
|
|
||||||
{
|
{
|
||||||
var track = _trackService.GetTrack(id);
|
var track = _trackService.GetTrack(id);
|
||||||
var resource = MapToResource(track, true, true);
|
var resource = MapToResource(track, true, true);
|
||||||
|
@ -103,6 +88,7 @@ namespace Lidarr.Api.V1.Tracks
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(TrackImportedEvent message)
|
public void Handle(TrackImportedEvent message)
|
||||||
{
|
{
|
||||||
foreach (var track in message.TrackInfo.Tracks)
|
foreach (var track in message.TrackInfo.Tracks)
|
||||||
|
@ -112,6 +98,7 @@ namespace Lidarr.Api.V1.Tracks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
public void Handle(TrackFileDeletedEvent message)
|
public void Handle(TrackFileDeletedEvent message)
|
||||||
{
|
{
|
||||||
foreach (var track in message.TrackFile.Tracks.Value)
|
foreach (var track in message.TrackFile.Tracks.Value)
|
|
@ -1,65 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Lidarr.Http.REST;
|
|
||||||
using Nancy;
|
|
||||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
|
||||||
using NzbDrone.Core.Music;
|
|
||||||
using NzbDrone.SignalR;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Tracks
|
|
||||||
{
|
|
||||||
public class TrackModule : TrackModuleWithSignalR
|
|
||||||
{
|
|
||||||
public TrackModule(IArtistService artistService,
|
|
||||||
ITrackService trackService,
|
|
||||||
IUpgradableSpecification upgradableSpecification,
|
|
||||||
IBroadcastSignalRMessage signalRBroadcaster)
|
|
||||||
: base(trackService, artistService, upgradableSpecification, signalRBroadcaster)
|
|
||||||
{
|
|
||||||
GetResourceAll = GetTracks;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<TrackResource> GetTracks()
|
|
||||||
{
|
|
||||||
var artistIdQuery = Request.Query.ArtistId;
|
|
||||||
var albumIdQuery = Request.Query.AlbumId;
|
|
||||||
var albumReleaseIdQuery = Request.Query.AlbumReleaseId;
|
|
||||||
var trackIdsQuery = Request.Query.TrackIds;
|
|
||||||
|
|
||||||
if (!artistIdQuery.HasValue && !trackIdsQuery.HasValue && !albumIdQuery.HasValue && !albumReleaseIdQuery.HasValue)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("One of artistId, albumId, albumReleaseId or trackIds must be provided");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (artistIdQuery.HasValue && !albumIdQuery.HasValue)
|
|
||||||
{
|
|
||||||
int artistId = Convert.ToInt32(artistIdQuery.Value);
|
|
||||||
|
|
||||||
return MapToResource(_trackService.GetTracksByArtist(artistId), false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (albumReleaseIdQuery.HasValue)
|
|
||||||
{
|
|
||||||
int releaseId = Convert.ToInt32(albumReleaseIdQuery.Value);
|
|
||||||
|
|
||||||
return MapToResource(_trackService.GetTracksByRelease(releaseId), false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (albumIdQuery.HasValue)
|
|
||||||
{
|
|
||||||
int albumId = Convert.ToInt32(albumIdQuery.Value);
|
|
||||||
|
|
||||||
return MapToResource(_trackService.GetTracksByAlbum(albumId), false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
string trackIdsValue = trackIdsQuery.Value.ToString();
|
|
||||||
|
|
||||||
var trackIds = trackIdsValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Select(e => Convert.ToInt32(e))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
return MapToResource(_trackService.GetTracks(trackIds), false, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +1,24 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Core.Update;
|
using NzbDrone.Core.Update;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Update
|
namespace Lidarr.Api.V1.Update
|
||||||
{
|
{
|
||||||
public class UpdateModule : LidarrRestModule<UpdateResource>
|
[V1ApiController]
|
||||||
|
public class UpdateController : Controller
|
||||||
{
|
{
|
||||||
private readonly IRecentUpdateProvider _recentUpdateProvider;
|
private readonly IRecentUpdateProvider _recentUpdateProvider;
|
||||||
|
|
||||||
public UpdateModule(IRecentUpdateProvider recentUpdateProvider)
|
public UpdateController(IRecentUpdateProvider recentUpdateProvider)
|
||||||
{
|
{
|
||||||
_recentUpdateProvider = recentUpdateProvider;
|
_recentUpdateProvider = recentUpdateProvider;
|
||||||
GetResourceAll = GetRecentUpdates;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<UpdateResource> GetRecentUpdates()
|
[HttpGet]
|
||||||
|
public List<UpdateResource> GetRecentUpdates()
|
||||||
{
|
{
|
||||||
var resources = _recentUpdateProvider.GetRecentUpdatePackages()
|
var resources = _recentUpdateProvider.GetRecentUpdatePackages()
|
||||||
.OrderByDescending(u => u.Version)
|
.OrderByDescending(u => u.Version)
|
|
@ -2,6 +2,7 @@ using System.Linq;
|
||||||
using Lidarr.Api.V1.Albums;
|
using Lidarr.Api.V1.Albums;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.Extensions;
|
using Lidarr.Http.Extensions;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.ArtistStats;
|
using NzbDrone.Core.ArtistStats;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||||
|
@ -11,24 +12,26 @@ using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Wanted
|
namespace Lidarr.Api.V1.Wanted
|
||||||
{
|
{
|
||||||
public class CutoffModule : AlbumModuleWithSignalR
|
[V1ApiController("wanted/cutoff")]
|
||||||
|
public class CutoffController : AlbumControllerWithSignalR
|
||||||
{
|
{
|
||||||
private readonly IAlbumCutoffService _albumCutoffService;
|
private readonly IAlbumCutoffService _albumCutoffService;
|
||||||
|
|
||||||
public CutoffModule(IAlbumCutoffService albumCutoffService,
|
public CutoffController(IAlbumCutoffService albumCutoffService,
|
||||||
IAlbumService albumService,
|
IAlbumService albumService,
|
||||||
IArtistStatisticsService artistStatisticsService,
|
IArtistStatisticsService artistStatisticsService,
|
||||||
IMapCoversToLocal coverMapper,
|
IMapCoversToLocal coverMapper,
|
||||||
IUpgradableSpecification upgradableSpecification,
|
IUpgradableSpecification upgradableSpecification,
|
||||||
IBroadcastSignalRMessage signalRBroadcaster)
|
IBroadcastSignalRMessage signalRBroadcaster)
|
||||||
: base(albumService, artistStatisticsService, coverMapper, upgradableSpecification, signalRBroadcaster, "wanted/cutoff")
|
: base(albumService, artistStatisticsService, coverMapper, upgradableSpecification, signalRBroadcaster)
|
||||||
{
|
{
|
||||||
_albumCutoffService = albumCutoffService;
|
_albumCutoffService = albumCutoffService;
|
||||||
GetResourcePaged = GetCutoffUnmetAlbums;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PagingResource<AlbumResource> GetCutoffUnmetAlbums(PagingResource<AlbumResource> pagingResource)
|
[HttpGet]
|
||||||
|
public PagingResource<AlbumResource> GetCutoffUnmetAlbums(bool includeArtist = false)
|
||||||
{
|
{
|
||||||
|
var pagingResource = Request.ReadPagingResourceFromRequest<AlbumResource>();
|
||||||
var pagingSpec = new PagingSpec<Album>
|
var pagingSpec = new PagingSpec<Album>
|
||||||
{
|
{
|
||||||
Page = pagingResource.Page,
|
Page = pagingResource.Page,
|
||||||
|
@ -37,7 +40,6 @@ namespace Lidarr.Api.V1.Wanted
|
||||||
SortDirection = pagingResource.SortDirection
|
SortDirection = pagingResource.SortDirection
|
||||||
};
|
};
|
||||||
|
|
||||||
var includeArtist = Request.GetBooleanQueryParameter("includeArtist");
|
|
||||||
var filter = pagingResource.Filters.FirstOrDefault(f => f.Key == "monitored");
|
var filter = pagingResource.Filters.FirstOrDefault(f => f.Key == "monitored");
|
||||||
|
|
||||||
if (filter != null && filter.Value == "false")
|
if (filter != null && filter.Value == "false")
|
||||||
|
@ -49,9 +51,7 @@ namespace Lidarr.Api.V1.Wanted
|
||||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Artist.Value.Monitored == true);
|
pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Artist.Value.Monitored == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
var resource = ApplyToPage(_albumCutoffService.AlbumsWhereCutoffUnmet, pagingSpec, v => MapToResource(v, includeArtist));
|
return pagingSpec.ApplyToPage(_albumCutoffService.AlbumsWhereCutoffUnmet, v => MapToResource(v, includeArtist));
|
||||||
|
|
||||||
return resource;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@ using System.Linq;
|
||||||
using Lidarr.Api.V1.Albums;
|
using Lidarr.Api.V1.Albums;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.Extensions;
|
using Lidarr.Http.Extensions;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.ArtistStats;
|
using NzbDrone.Core.ArtistStats;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||||
|
@ -11,20 +12,22 @@ using NzbDrone.SignalR;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Wanted
|
namespace Lidarr.Api.V1.Wanted
|
||||||
{
|
{
|
||||||
public class MissingModule : AlbumModuleWithSignalR
|
[V1ApiController("wanted/missing")]
|
||||||
|
public class MissingController : AlbumControllerWithSignalR
|
||||||
{
|
{
|
||||||
public MissingModule(IAlbumService albumService,
|
public MissingController(IAlbumService albumService,
|
||||||
IArtistStatisticsService artistStatisticsService,
|
IArtistStatisticsService artistStatisticsService,
|
||||||
IMapCoversToLocal coverMapper,
|
IMapCoversToLocal coverMapper,
|
||||||
IUpgradableSpecification upgradableSpecification,
|
IUpgradableSpecification upgradableSpecification,
|
||||||
IBroadcastSignalRMessage signalRBroadcaster)
|
IBroadcastSignalRMessage signalRBroadcaster)
|
||||||
: base(albumService, artistStatisticsService, coverMapper, upgradableSpecification, signalRBroadcaster, "wanted/missing")
|
: base(albumService, artistStatisticsService, coverMapper, upgradableSpecification, signalRBroadcaster)
|
||||||
{
|
{
|
||||||
GetResourcePaged = GetMissingAlbums;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PagingResource<AlbumResource> GetMissingAlbums(PagingResource<AlbumResource> pagingResource)
|
[HttpGet]
|
||||||
|
public PagingResource<AlbumResource> GetMissingAlbums(bool includeArtist = false)
|
||||||
{
|
{
|
||||||
|
var pagingResource = Request.ReadPagingResourceFromRequest<AlbumResource>();
|
||||||
var pagingSpec = new PagingSpec<Album>
|
var pagingSpec = new PagingSpec<Album>
|
||||||
{
|
{
|
||||||
Page = pagingResource.Page,
|
Page = pagingResource.Page,
|
||||||
|
@ -33,7 +36,6 @@ namespace Lidarr.Api.V1.Wanted
|
||||||
SortDirection = pagingResource.SortDirection
|
SortDirection = pagingResource.SortDirection
|
||||||
};
|
};
|
||||||
|
|
||||||
var includeArtist = Request.GetBooleanQueryParameter("includeArtist");
|
|
||||||
var monitoredFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "monitored");
|
var monitoredFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "monitored");
|
||||||
|
|
||||||
if (monitoredFilter != null && monitoredFilter.Value == "false")
|
if (monitoredFilter != null && monitoredFilter.Value == "false")
|
||||||
|
@ -45,9 +47,7 @@ namespace Lidarr.Api.V1.Wanted
|
||||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Artist.Value.Monitored == true);
|
pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Artist.Value.Monitored == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
var resource = ApplyToPage(_albumService.AlbumsWithoutFiles, pagingSpec, v => MapToResource(v, includeArtist));
|
return pagingSpec.ApplyToPage(_albumService.AlbumsWithoutFiles, v => MapToResource(v, includeArtist));
|
||||||
|
|
||||||
return resource;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace Lidarr.Http.Authentication
|
||||||
|
{
|
||||||
|
public class ApiKeyAuthenticationOptions : AuthenticationSchemeOptions
|
||||||
|
{
|
||||||
|
public const string DefaultScheme = "API Key";
|
||||||
|
public string Scheme => DefaultScheme;
|
||||||
|
public string AuthenticationType = DefaultScheme;
|
||||||
|
|
||||||
|
public string HeaderName { get; set; }
|
||||||
|
public string QueryName { get; set; }
|
||||||
|
public string ApiKey { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ApiKeyAuthenticationHandler : AuthenticationHandler<ApiKeyAuthenticationOptions>
|
||||||
|
{
|
||||||
|
public ApiKeyAuthenticationHandler(IOptionsMonitor<ApiKeyAuthenticationOptions> options,
|
||||||
|
ILoggerFactory logger,
|
||||||
|
UrlEncoder encoder,
|
||||||
|
ISystemClock clock)
|
||||||
|
: base(options, logger, encoder, clock)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ParseApiKey()
|
||||||
|
{
|
||||||
|
// Try query parameter
|
||||||
|
if (Request.Query.TryGetValue(Options.QueryName, out var value))
|
||||||
|
{
|
||||||
|
return value.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
// No ApiKey query parameter found try headers
|
||||||
|
if (Request.Headers.TryGetValue(Options.HeaderName, out var headerValue))
|
||||||
|
{
|
||||||
|
return headerValue.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Request.Headers["Authorization"].FirstOrDefault()?.Replace("Bearer ", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||||
|
{
|
||||||
|
var providedApiKey = ParseApiKey();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(providedApiKey))
|
||||||
|
{
|
||||||
|
return Task.FromResult(AuthenticateResult.NoResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Options.ApiKey == providedApiKey)
|
||||||
|
{
|
||||||
|
var claims = new List<Claim>
|
||||||
|
{
|
||||||
|
new Claim("ApiKey", "true")
|
||||||
|
};
|
||||||
|
|
||||||
|
var identity = new ClaimsIdentity(claims, Options.AuthenticationType);
|
||||||
|
var identities = new List<ClaimsIdentity> { identity };
|
||||||
|
var principal = new ClaimsPrincipal(identities);
|
||||||
|
var ticket = new AuthenticationTicket(principal, Options.Scheme);
|
||||||
|
|
||||||
|
return Task.FromResult(AuthenticateResult.Success(ticket));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(AuthenticateResult.NoResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
|
||||||
|
{
|
||||||
|
Response.StatusCode = 401;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task HandleForbiddenAsync(AuthenticationProperties properties)
|
||||||
|
{
|
||||||
|
Response.StatusCode = 403;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using NzbDrone.Core.Authentication;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
|
||||||
|
namespace Lidarr.Http.Authentication
|
||||||
|
{
|
||||||
|
public static class AuthenticationBuilderExtensions
|
||||||
|
{
|
||||||
|
public static AuthenticationBuilder AddApiKey(this AuthenticationBuilder authenticationBuilder, string name, Action<ApiKeyAuthenticationOptions> options)
|
||||||
|
{
|
||||||
|
return authenticationBuilder.AddScheme<ApiKeyAuthenticationOptions, ApiKeyAuthenticationHandler>(name, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AuthenticationBuilder AddBasicAuthentication(this AuthenticationBuilder authenticationBuilder)
|
||||||
|
{
|
||||||
|
return authenticationBuilder.AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>(AuthenticationType.Basic.ToString(), options => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AuthenticationBuilder AddNoAuthentication(this AuthenticationBuilder authenticationBuilder)
|
||||||
|
{
|
||||||
|
return authenticationBuilder.AddScheme<AuthenticationSchemeOptions, NoAuthenticationHandler>(AuthenticationType.None.ToString(), options => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AuthenticationBuilder AddAppAuthentication(this IServiceCollection services, IConfigFileProvider config)
|
||||||
|
{
|
||||||
|
var authBuilder = services.AddAuthentication(config.AuthenticationMethod.ToString());
|
||||||
|
|
||||||
|
if (config.AuthenticationMethod == AuthenticationType.Basic)
|
||||||
|
{
|
||||||
|
authBuilder.AddBasicAuthentication();
|
||||||
|
}
|
||||||
|
else if (config.AuthenticationMethod == AuthenticationType.Forms)
|
||||||
|
{
|
||||||
|
authBuilder.AddCookie(AuthenticationType.Forms.ToString(), options =>
|
||||||
|
{
|
||||||
|
options.AccessDeniedPath = "/login?loginFailed=true";
|
||||||
|
options.LoginPath = "/login";
|
||||||
|
options.ExpireTimeSpan = TimeSpan.FromDays(7);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
authBuilder.AddNoAuthentication();
|
||||||
|
}
|
||||||
|
|
||||||
|
authBuilder.AddApiKey("API", options =>
|
||||||
|
{
|
||||||
|
options.HeaderName = "X-Api-Key";
|
||||||
|
options.QueryName = "apikey";
|
||||||
|
options.ApiKey = config.ApiKey;
|
||||||
|
});
|
||||||
|
|
||||||
|
authBuilder.AddApiKey("SignalR", options =>
|
||||||
|
{
|
||||||
|
options.HeaderName = "X-Api-Key";
|
||||||
|
options.QueryName = "access_token";
|
||||||
|
options.ApiKey = config.ApiKey;
|
||||||
|
});
|
||||||
|
|
||||||
|
return authBuilder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
src/Lidarr.Http/Authentication/AuthenticationController.cs
Normal file
58
src/Lidarr.Http/Authentication/AuthenticationController.cs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
|
||||||
|
namespace Lidarr.Http.Authentication
|
||||||
|
{
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ApiController]
|
||||||
|
public class AuthenticationController : Controller
|
||||||
|
{
|
||||||
|
private readonly IAuthenticationService _authService;
|
||||||
|
private readonly IConfigFileProvider _configFileProvider;
|
||||||
|
|
||||||
|
public AuthenticationController(IAuthenticationService authService, IConfigFileProvider configFileProvider)
|
||||||
|
{
|
||||||
|
_authService = authService;
|
||||||
|
_configFileProvider = configFileProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("login")]
|
||||||
|
public async Task<IActionResult> Login([FromForm] LoginResource resource, [FromQuery] string returnUrl = null)
|
||||||
|
{
|
||||||
|
var user = _authService.Login(HttpContext.Request, resource.Username, resource.Password);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return Redirect($"~/login?returnUrl={returnUrl}&loginFailed=true");
|
||||||
|
}
|
||||||
|
|
||||||
|
var claims = new List<Claim>
|
||||||
|
{
|
||||||
|
new Claim("user", user.Username),
|
||||||
|
new Claim("identifier", user.Identifier.ToString()),
|
||||||
|
new Claim("UiAuth", "true")
|
||||||
|
};
|
||||||
|
|
||||||
|
var authProperties = new AuthenticationProperties
|
||||||
|
{
|
||||||
|
IsPersistent = resource.RememberMe == "on"
|
||||||
|
};
|
||||||
|
await HttpContext.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity(claims, "Cookies", "user", "identifier")), authProperties);
|
||||||
|
|
||||||
|
return Redirect("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("logout")]
|
||||||
|
public async Task<IActionResult> Logout()
|
||||||
|
{
|
||||||
|
_authService.Logout(HttpContext);
|
||||||
|
await HttpContext.SignOutAsync();
|
||||||
|
return Redirect("/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,50 +0,0 @@
|
||||||
using System;
|
|
||||||
using Nancy;
|
|
||||||
using Nancy.Authentication.Forms;
|
|
||||||
using Nancy.Extensions;
|
|
||||||
using Nancy.ModelBinding;
|
|
||||||
using NzbDrone.Core.Configuration;
|
|
||||||
|
|
||||||
namespace Lidarr.Http.Authentication
|
|
||||||
{
|
|
||||||
public class AuthenticationModule : NancyModule
|
|
||||||
{
|
|
||||||
private readonly IAuthenticationService _authService;
|
|
||||||
private readonly IConfigFileProvider _configFileProvider;
|
|
||||||
|
|
||||||
public AuthenticationModule(IAuthenticationService authService, IConfigFileProvider configFileProvider)
|
|
||||||
{
|
|
||||||
_authService = authService;
|
|
||||||
_configFileProvider = configFileProvider;
|
|
||||||
Post("/login", x => Login(this.Bind<LoginResource>()));
|
|
||||||
Get("/logout", x => Logout());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Response Login(LoginResource resource)
|
|
||||||
{
|
|
||||||
var user = _authService.Login(Context, resource.Username, resource.Password);
|
|
||||||
|
|
||||||
if (user == null)
|
|
||||||
{
|
|
||||||
var returnUrl = (string)Request.Query.returnUrl;
|
|
||||||
return Context.GetRedirect($"~/login?returnUrl={returnUrl}&loginFailed=true");
|
|
||||||
}
|
|
||||||
|
|
||||||
DateTime? expiry = null;
|
|
||||||
|
|
||||||
if (resource.RememberMe)
|
|
||||||
{
|
|
||||||
expiry = DateTime.UtcNow.AddDays(7);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.LoginAndRedirect(user.Identifier, expiry, _configFileProvider.UrlBase + "/");
|
|
||||||
}
|
|
||||||
|
|
||||||
private Response Logout()
|
|
||||||
{
|
|
||||||
_authService.Logout(Context);
|
|
||||||
|
|
||||||
return this.LogoutAndRedirect(_configFileProvider.UrlBase + "/");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +1,16 @@
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Security.Claims;
|
|
||||||
using System.Security.Principal;
|
|
||||||
using Lidarr.Http.Extensions;
|
using Lidarr.Http.Extensions;
|
||||||
using Nancy;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Nancy.Authentication.Basic;
|
|
||||||
using Nancy.Authentication.Forms;
|
|
||||||
using Nancy.Routing.Trie.Nodes;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Extensions;
|
|
||||||
using NzbDrone.Core.Authentication;
|
using NzbDrone.Core.Authentication;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
|
|
||||||
namespace Lidarr.Http.Authentication
|
namespace Lidarr.Http.Authentication
|
||||||
{
|
{
|
||||||
public interface IAuthenticationService : IUserValidator, IUserMapper
|
public interface IAuthenticationService
|
||||||
{
|
{
|
||||||
void SetContext(NancyContext context);
|
void LogUnauthorized(HttpRequest context);
|
||||||
|
User Login(HttpRequest request, string username, string password);
|
||||||
void LogUnauthorized(NancyContext context);
|
void Logout(HttpContext context);
|
||||||
User Login(NancyContext context, string username, string password);
|
|
||||||
void Logout(NancyContext context);
|
|
||||||
bool IsAuthenticated(NancyContext context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AuthenticationService : IAuthenticationService
|
public class AuthenticationService : IAuthenticationService
|
||||||
|
@ -34,9 +22,6 @@ namespace Lidarr.Http.Authentication
|
||||||
private static string API_KEY;
|
private static string API_KEY;
|
||||||
private static AuthenticationType AUTH_METHOD;
|
private static AuthenticationType AUTH_METHOD;
|
||||||
|
|
||||||
[ThreadStatic]
|
|
||||||
private static NancyContext _context;
|
|
||||||
|
|
||||||
public AuthenticationService(IConfigFileProvider configFileProvider, IUserService userService)
|
public AuthenticationService(IConfigFileProvider configFileProvider, IUserService userService)
|
||||||
{
|
{
|
||||||
_userService = userService;
|
_userService = userService;
|
||||||
|
@ -44,13 +29,7 @@ namespace Lidarr.Http.Authentication
|
||||||
AUTH_METHOD = configFileProvider.AuthenticationMethod;
|
AUTH_METHOD = configFileProvider.AuthenticationMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetContext(NancyContext context)
|
public User Login(HttpRequest request, string username, string password)
|
||||||
{
|
|
||||||
// Validate and GetUserIdentifier don't have access to the NancyContext so get it from the pipeline earlier
|
|
||||||
_context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public User Login(NancyContext context, string username, string password)
|
|
||||||
{
|
{
|
||||||
if (AUTH_METHOD == AuthenticationType.None)
|
if (AUTH_METHOD == AuthenticationType.None)
|
||||||
{
|
{
|
||||||
|
@ -61,179 +40,50 @@ namespace Lidarr.Http.Authentication
|
||||||
|
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
LogSuccess(context, username);
|
LogSuccess(request, username);
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogFailure(context, username);
|
LogFailure(request, username);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Logout(NancyContext context)
|
public void Logout(HttpContext context)
|
||||||
{
|
{
|
||||||
if (AUTH_METHOD == AuthenticationType.None)
|
if (AUTH_METHOD == AuthenticationType.None)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.CurrentUser != null)
|
if (context.User != null)
|
||||||
{
|
{
|
||||||
LogLogout(context, context.CurrentUser.Identity.Name);
|
LogLogout(context.Request, context.User.Identity.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClaimsPrincipal Validate(string username, string password)
|
public void LogUnauthorized(HttpRequest context)
|
||||||
{
|
{
|
||||||
if (AUTH_METHOD == AuthenticationType.None)
|
_authLogger.Info("Auth-Unauthorized ip {0} url '{1}'", context.GetRemoteIP(), context.Path);
|
||||||
{
|
|
||||||
return new ClaimsPrincipal(new GenericIdentity(AnonymousUser));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var user = _userService.FindUser(username, password);
|
private void LogInvalidated(HttpRequest context)
|
||||||
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
if (AUTH_METHOD != AuthenticationType.Basic)
|
|
||||||
{
|
|
||||||
// Don't log success for basic auth
|
|
||||||
LogSuccess(_context, username);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ClaimsPrincipal(new GenericIdentity(user.Username));
|
|
||||||
}
|
|
||||||
|
|
||||||
LogFailure(_context, username);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClaimsPrincipal GetUserFromIdentifier(Guid identifier, NancyContext context)
|
|
||||||
{
|
|
||||||
if (AUTH_METHOD == AuthenticationType.None)
|
|
||||||
{
|
|
||||||
return new ClaimsPrincipal(new GenericIdentity(AnonymousUser));
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = _userService.FindUser(identifier);
|
|
||||||
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
return new ClaimsPrincipal(new GenericIdentity(user.Username));
|
|
||||||
}
|
|
||||||
|
|
||||||
LogInvalidated(_context);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsAuthenticated(NancyContext context)
|
|
||||||
{
|
|
||||||
var apiKey = GetApiKey(context);
|
|
||||||
|
|
||||||
if (context.Request.IsApiRequest())
|
|
||||||
{
|
|
||||||
return ValidApiKey(apiKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AUTH_METHOD == AuthenticationType.None)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.Request.IsFeedRequest())
|
|
||||||
{
|
|
||||||
if (ValidUser(context) || ValidApiKey(apiKey))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.Request.IsLoginRequest())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.Request.IsContentRequest())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.Request.IsBundledJsRequest())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ValidUser(context))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ValidUser(NancyContext context)
|
|
||||||
{
|
|
||||||
if (context.CurrentUser != null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ValidApiKey(string apiKey)
|
|
||||||
{
|
|
||||||
if (API_KEY.Equals(apiKey))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetApiKey(NancyContext context)
|
|
||||||
{
|
|
||||||
var apiKeyHeader = context.Request.Headers["X-Api-Key"].FirstOrDefault();
|
|
||||||
var apiKeyQueryString = context.Request.Query["ApiKey"];
|
|
||||||
|
|
||||||
if (!apiKeyHeader.IsNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
return apiKeyHeader;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (apiKeyQueryString.HasValue)
|
|
||||||
{
|
|
||||||
return apiKeyQueryString.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.Request.Headers.Authorization;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LogUnauthorized(NancyContext context)
|
|
||||||
{
|
|
||||||
_authLogger.Info("Auth-Unauthorized ip {0} url '{1}'", context.GetRemoteIP(), context.Request.Url.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LogInvalidated(NancyContext context)
|
|
||||||
{
|
{
|
||||||
_authLogger.Info("Auth-Invalidated ip {0}", context.GetRemoteIP());
|
_authLogger.Info("Auth-Invalidated ip {0}", context.GetRemoteIP());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogFailure(NancyContext context, string username)
|
private void LogFailure(HttpRequest context, string username)
|
||||||
{
|
{
|
||||||
_authLogger.Warn("Auth-Failure ip {0} username '{1}'", context.GetRemoteIP(), username);
|
_authLogger.Warn("Auth-Failure ip {0} username '{1}'", context.GetRemoteIP(), username);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogSuccess(NancyContext context, string username)
|
private void LogSuccess(HttpRequest context, string username)
|
||||||
{
|
{
|
||||||
_authLogger.Info("Auth-Success ip {0} username '{1}'", context.GetRemoteIP(), username);
|
_authLogger.Info("Auth-Success ip {0} username '{1}'", context.GetRemoteIP(), username);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogLogout(NancyContext context, string username)
|
private void LogLogout(HttpRequest context, string username)
|
||||||
{
|
{
|
||||||
_authLogger.Info("Auth-Logout ip {0} username '{1}'", context.GetRemoteIP(), username);
|
_authLogger.Info("Auth-Logout ip {0} username '{1}'", context.GetRemoteIP(), username);
|
||||||
}
|
}
|
||||||
|
|
84
src/Lidarr.Http/Authentication/BasicAuthenticationHandler.cs
Normal file
84
src/Lidarr.Http/Authentication/BasicAuthenticationHandler.cs
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
|
|
||||||
|
namespace Lidarr.Http.Authentication
|
||||||
|
{
|
||||||
|
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
|
||||||
|
{
|
||||||
|
private readonly IAuthenticationService _authService;
|
||||||
|
|
||||||
|
public BasicAuthenticationHandler(IAuthenticationService authService,
|
||||||
|
IOptionsMonitor<AuthenticationSchemeOptions> options,
|
||||||
|
ILoggerFactory logger,
|
||||||
|
UrlEncoder encoder,
|
||||||
|
ISystemClock clock)
|
||||||
|
: base(options, logger, encoder, clock)
|
||||||
|
{
|
||||||
|
_authService = authService;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||||
|
{
|
||||||
|
if (!Request.Headers.ContainsKey("Authorization"))
|
||||||
|
{
|
||||||
|
return Task.FromResult(AuthenticateResult.Fail("Authorization header missing."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get authorization key
|
||||||
|
var authorizationHeader = Request.Headers["Authorization"].ToString();
|
||||||
|
var authHeaderRegex = new Regex(@"Basic (.*)");
|
||||||
|
|
||||||
|
if (!authHeaderRegex.IsMatch(authorizationHeader))
|
||||||
|
{
|
||||||
|
return Task.FromResult(AuthenticateResult.Fail("Authorization code not formatted properly."));
|
||||||
|
}
|
||||||
|
|
||||||
|
var authBase64 = Encoding.UTF8.GetString(Convert.FromBase64String(authHeaderRegex.Replace(authorizationHeader, "$1")));
|
||||||
|
var authSplit = authBase64.Split(':', 2);
|
||||||
|
var authUsername = authSplit[0];
|
||||||
|
var authPassword = authSplit.Length > 1 ? authSplit[1] : throw new Exception("Unable to get password");
|
||||||
|
|
||||||
|
var user = _authService.Login(Request, authUsername, authPassword);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return Task.FromResult(AuthenticateResult.Fail("The username or password is not correct."));
|
||||||
|
}
|
||||||
|
|
||||||
|
var claims = new List<Claim>
|
||||||
|
{
|
||||||
|
new Claim("user", user.Username),
|
||||||
|
new Claim("identifier", user.Identifier.ToString()),
|
||||||
|
new Claim("UiAuth", "true")
|
||||||
|
};
|
||||||
|
|
||||||
|
var identity = new ClaimsIdentity(claims, "Basic", "user", "identifier");
|
||||||
|
var principal = new ClaimsPrincipal(identity);
|
||||||
|
var ticket = new AuthenticationTicket(principal, "Basic");
|
||||||
|
|
||||||
|
return Task.FromResult(AuthenticateResult.Success(ticket));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
|
||||||
|
{
|
||||||
|
Response.Headers.Add("WWW-Authenticate", $"Basic realm=\"{BuildInfo.AppName}\"");
|
||||||
|
Response.StatusCode = 401;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task HandleForbiddenAsync(AuthenticationProperties properties)
|
||||||
|
{
|
||||||
|
Response.StatusCode = 403;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,142 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Text;
|
|
||||||
using Lidarr.Http.Extensions;
|
|
||||||
using Lidarr.Http.Extensions.Pipelines;
|
|
||||||
using Nancy;
|
|
||||||
using Nancy.Authentication.Basic;
|
|
||||||
using Nancy.Authentication.Forms;
|
|
||||||
using Nancy.Bootstrapper;
|
|
||||||
using Nancy.Cryptography;
|
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
|
||||||
using NzbDrone.Common.Extensions;
|
|
||||||
using NzbDrone.Core.Authentication;
|
|
||||||
using NzbDrone.Core.Configuration;
|
|
||||||
|
|
||||||
namespace Lidarr.Http.Authentication
|
|
||||||
{
|
|
||||||
public class EnableAuthInNancy : IRegisterNancyPipeline
|
|
||||||
{
|
|
||||||
private readonly IAuthenticationService _authenticationService;
|
|
||||||
private readonly IConfigService _configService;
|
|
||||||
private readonly IConfigFileProvider _configFileProvider;
|
|
||||||
private FormsAuthenticationConfiguration _formsAuthConfig;
|
|
||||||
|
|
||||||
public EnableAuthInNancy(IAuthenticationService authenticationService,
|
|
||||||
IConfigService configService,
|
|
||||||
IConfigFileProvider configFileProvider)
|
|
||||||
{
|
|
||||||
_authenticationService = authenticationService;
|
|
||||||
_configService = configService;
|
|
||||||
_configFileProvider = configFileProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Order => 10;
|
|
||||||
|
|
||||||
public void Register(IPipelines pipelines)
|
|
||||||
{
|
|
||||||
if (_configFileProvider.AuthenticationMethod == AuthenticationType.Forms)
|
|
||||||
{
|
|
||||||
RegisterFormsAuth(pipelines);
|
|
||||||
pipelines.AfterRequest.AddItemToEndOfPipeline(SlidingAuthenticationForFormsAuth);
|
|
||||||
}
|
|
||||||
else if (_configFileProvider.AuthenticationMethod == AuthenticationType.Basic)
|
|
||||||
{
|
|
||||||
pipelines.EnableBasicAuthentication(new BasicAuthenticationConfiguration(_authenticationService, BuildInfo.AppName));
|
|
||||||
pipelines.BeforeRequest.AddItemToStartOfPipeline(CaptureContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
pipelines.BeforeRequest.AddItemToEndOfPipeline(RequiresAuthentication);
|
|
||||||
pipelines.AfterRequest.AddItemToEndOfPipeline(RemoveLoginHooksForApiCalls);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Response CaptureContext(NancyContext context)
|
|
||||||
{
|
|
||||||
_authenticationService.SetContext(context);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Response RequiresAuthentication(NancyContext context)
|
|
||||||
{
|
|
||||||
Response response = null;
|
|
||||||
|
|
||||||
if (!_authenticationService.IsAuthenticated(context))
|
|
||||||
{
|
|
||||||
_authenticationService.LogUnauthorized(context);
|
|
||||||
response = new Response { StatusCode = HttpStatusCode.Unauthorized };
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RegisterFormsAuth(IPipelines pipelines)
|
|
||||||
{
|
|
||||||
FormsAuthentication.FormsAuthenticationCookieName = "LidarrAuth";
|
|
||||||
|
|
||||||
var cryptographyConfiguration = new CryptographyConfiguration(
|
|
||||||
new AesEncryptionProvider(new PassphraseKeyGenerator(_configService.RijndaelPassphrase, Encoding.ASCII.GetBytes(_configService.RijndaelSalt))),
|
|
||||||
new DefaultHmacProvider(new PassphraseKeyGenerator(_configService.HmacPassphrase, Encoding.ASCII.GetBytes(_configService.HmacSalt))));
|
|
||||||
|
|
||||||
_formsAuthConfig = new FormsAuthenticationConfiguration
|
|
||||||
{
|
|
||||||
RedirectUrl = _configFileProvider.UrlBase + "/login",
|
|
||||||
UserMapper = _authenticationService,
|
|
||||||
Path = GetCookiePath(),
|
|
||||||
CryptographyConfiguration = cryptographyConfiguration
|
|
||||||
};
|
|
||||||
|
|
||||||
FormsAuthentication.Enable(pipelines, _formsAuthConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveLoginHooksForApiCalls(NancyContext context)
|
|
||||||
{
|
|
||||||
if (context.Request.IsApiRequest())
|
|
||||||
{
|
|
||||||
if ((context.Response.StatusCode == HttpStatusCode.SeeOther &&
|
|
||||||
context.Response.Headers["Location"].StartsWith($"{_configFileProvider.UrlBase}/login", StringComparison.InvariantCultureIgnoreCase)) ||
|
|
||||||
context.Response.StatusCode == HttpStatusCode.Unauthorized)
|
|
||||||
{
|
|
||||||
context.Response = new { Error = "Unauthorized" }.AsResponse(context, HttpStatusCode.Unauthorized);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SlidingAuthenticationForFormsAuth(NancyContext context)
|
|
||||||
{
|
|
||||||
if (context.CurrentUser == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var formsAuthCookieName = FormsAuthentication.FormsAuthenticationCookieName;
|
|
||||||
|
|
||||||
if (!context.Request.Path.Equals("/logout") &&
|
|
||||||
context.Request.Cookies.ContainsKey(formsAuthCookieName))
|
|
||||||
{
|
|
||||||
var formsAuthCookieValue = context.Request.Cookies[formsAuthCookieName];
|
|
||||||
|
|
||||||
if (FormsAuthentication.DecryptAndValidateAuthenticationCookie(formsAuthCookieValue, _formsAuthConfig).IsNotNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
var formsAuthCookie = new LidarrNancyCookie(formsAuthCookieName, formsAuthCookieValue, true, false, DateTime.UtcNow.AddDays(7))
|
|
||||||
{
|
|
||||||
Path = GetCookiePath()
|
|
||||||
};
|
|
||||||
|
|
||||||
context.Response.WithCookie(formsAuthCookie);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetCookiePath()
|
|
||||||
{
|
|
||||||
var urlBase = _configFileProvider.UrlBase;
|
|
||||||
|
|
||||||
if (urlBase.IsNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
return "/";
|
|
||||||
}
|
|
||||||
|
|
||||||
return urlBase;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
using System;
|
|
||||||
using Nancy.Cookies;
|
|
||||||
|
|
||||||
namespace Lidarr.Http.Authentication
|
|
||||||
{
|
|
||||||
public class LidarrNancyCookie : NancyCookie
|
|
||||||
{
|
|
||||||
public LidarrNancyCookie(string name, string value)
|
|
||||||
: base(name, value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public LidarrNancyCookie(string name, string value, DateTime expires)
|
|
||||||
: base(name, value, expires)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public LidarrNancyCookie(string name, string value, bool httpOnly)
|
|
||||||
: base(name, value, httpOnly)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public LidarrNancyCookie(string name, string value, bool httpOnly, bool secure)
|
|
||||||
: base(name, value, httpOnly, secure)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public LidarrNancyCookie(string name, string value, bool httpOnly, bool secure, DateTime? expires)
|
|
||||||
: base(name, value, httpOnly, secure, expires)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return base.ToString() + "; SameSite=Lax";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue