mirror of
https://github.com/sphildreth/roadie
synced 2025-02-17 21:48:27 +00:00
Delete Users Code Complete.
This commit is contained in:
parent
7606a604f8
commit
af71e4c9f2
40 changed files with 1198 additions and 1173 deletions
Roadie.Api.Library
Roadie.Api.Services
AdminService.csArtistService.csBookmarkService.csCollectionService.csHttpContext.csIAdminService.csIArtistService.csICollectionService.csIImageService.csIReleaseService.csITrackService.csImageService.csLabelService.csPlayActivityService.csPlaylistService.csReleaseService.csRoadie.Api.Services.csprojServiceBase.csStatisticsService.csSubsonicService.csTrackService.csUserService.cs
Roadie.Api
Controllers
AccountController.csAdminController.csArtistController.csCollectionController.csEntityControllerBase.csImageController.csLabelController.csLookupController.csPlayController.csPlaylistController.csReleaseController.csStatsController.csSubsonicController.csTrackController.csUserController.cs
Roadie.Api.csproj
|
@ -9,7 +9,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CsvHelper" Version="12.1.2" />
|
||||
<PackageReference Include="EFCore.BulkExtensions" Version="2.4.6" />
|
||||
<PackageReference Include="EFCore.BulkExtensions" Version="2.4.7" />
|
||||
<PackageReference Include="FluentFTP" Version="24.0.0" />
|
||||
<PackageReference Include="Hashids.net" Version="1.2.2" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.4" />
|
||||
|
@ -32,7 +32,7 @@
|
|||
<PackageReference Include="System.Drawing.Common" Version="4.5.1" />
|
||||
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.5.0" />
|
||||
<PackageReference Include="System.Runtime.Caching" Version="4.5.0" />
|
||||
<PackageReference Include="z440.atl.core" Version="2.9.0" />
|
||||
<PackageReference Include="z440.atl.core" Version="2.10.0" />
|
||||
<PackageReference Include="zlib.net-mutliplatform" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ namespace Roadie.Library.MetaData.ID3Tags
|
|||
result.Release = id3v2.Album;
|
||||
result.Artist = id3v2.AlbumArtist ?? id3v2.Artist;
|
||||
result.ArtistRaw = id3v2.AlbumArtist ?? id3v2.Artist;
|
||||
result.Genres = id3v2.Genre?.Split(new char[] { ',', '\\' });
|
||||
result.Genres = id3v2.Genre?.Split(new char[] { ',', '\\', ';', '|' });
|
||||
result.TrackArtist = id3v2.OriginalArtist ?? id3v2.Artist ?? id3v2.AlbumArtist;
|
||||
result.TrackArtistRaw = id3v2.OriginalArtist;
|
||||
result.AudioBitrate = (int?)audioFile.Bitrate;
|
||||
|
|
|
@ -19,7 +19,6 @@ using Roadie.Library.MetaData.FileName;
|
|||
using Roadie.Library.MetaData.ID3Tags;
|
||||
using Roadie.Library.MetaData.LastFm;
|
||||
using Roadie.Library.MetaData.MusicBrainz;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Processors;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
|
@ -89,45 +88,6 @@ namespace Roadie.Api.Services
|
|||
this.ArtistFactory = new ArtistFactory(configuration, httpEncoder, context, cacheManager, MessageLogger, this.ArtistLookupEngine, this.ReleaseFactory, this.ImageFactory, this.ReleaseLookupEngine, this.AudioMetaDataHelper);
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteArtistSecondaryImage(ApplicationUser user, Guid artistId, int index)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var artist = this.DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
|
||||
if (artist == null)
|
||||
{
|
||||
await this.LogAndPublish($"DeleteArtistSecondaryImage Unknown Artist [{ artistId}]", LogLevel.Warning);
|
||||
return new OperationResult<bool>(true, $"Artist Not Found [{ artistId }]");
|
||||
}
|
||||
try
|
||||
{
|
||||
var artistFolder = artist.ArtistFileFolder(this.Configuration, this.Configuration.LibraryFolder);
|
||||
var artistImagesInFolder = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly);
|
||||
var artistImageFilename = artistImagesInFolder.Skip(index).FirstOrDefault();
|
||||
if (artistImageFilename.Exists)
|
||||
{
|
||||
artistImageFilename.Delete();
|
||||
}
|
||||
this.CacheManager.ClearRegion(artist.CacheRegion);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
await this.LogAndPublish("Error deleting artist secondary image.");
|
||||
errors.Add(ex);
|
||||
}
|
||||
sw.Stop();
|
||||
await this.LogAndPublish($"DeleteArtistSecondaryImage `{ artist }` Index [{ index }], By User `{user }`", LogLevel.Information);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteArtist(ApplicationUser user, Guid artistId)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
|
@ -200,6 +160,80 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteArtistSecondaryImage(ApplicationUser user, Guid artistId, int index)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var artist = this.DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
|
||||
if (artist == null)
|
||||
{
|
||||
await this.LogAndPublish($"DeleteArtistSecondaryImage Unknown Artist [{ artistId}]", LogLevel.Warning);
|
||||
return new OperationResult<bool>(true, $"Artist Not Found [{ artistId }]");
|
||||
}
|
||||
try
|
||||
{
|
||||
var artistFolder = artist.ArtistFileFolder(this.Configuration, this.Configuration.LibraryFolder);
|
||||
var artistImagesInFolder = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly);
|
||||
var artistImageFilename = artistImagesInFolder.Skip(index).FirstOrDefault();
|
||||
if (artistImageFilename.Exists)
|
||||
{
|
||||
artistImageFilename.Delete();
|
||||
}
|
||||
this.CacheManager.ClearRegion(artist.CacheRegion);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
await this.LogAndPublish("Error deleting artist secondary image.");
|
||||
errors.Add(ex);
|
||||
}
|
||||
sw.Stop();
|
||||
await this.LogAndPublish($"DeleteArtistSecondaryImage `{ artist }` Index [{ index }], By User `{user }`", LogLevel.Information);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteRelease(ApplicationUser user, Guid releaseId, bool? doDeleteFiles)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var errors = new List<Exception>();
|
||||
|
||||
var release = this.DbContext.Releases.Include(x => x.Artist).FirstOrDefault(x => x.RoadieId == releaseId);
|
||||
try
|
||||
{
|
||||
if (release == null)
|
||||
{
|
||||
await this.LogAndPublish($"DeleteRelease Unknown Release [{ releaseId}]", LogLevel.Warning);
|
||||
return new OperationResult<bool>(true, $"Release Not Found [{ releaseId }]");
|
||||
}
|
||||
await this.ReleaseFactory.Delete(release, doDeleteFiles ?? false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
await this.LogAndPublish("Error deleting release.");
|
||||
errors.Add(ex);
|
||||
}
|
||||
sw.Stop();
|
||||
await this.LogAndPublish($"DeleteRelease `{ release }`, By User `{ user}`", LogLevel.Information);
|
||||
this.CacheManager.Clear();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteTrack(ApplicationUser user, Guid trackId, bool? doDeleteFile)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
|
@ -263,31 +297,39 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteRelease(ApplicationUser user, Guid releaseId, bool? doDeleteFiles)
|
||||
public async Task<OperationResult<bool>> DeleteUser(ApplicationUser applicationUser, Guid userId)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var errors = new List<Exception>();
|
||||
|
||||
var release = this.DbContext.Releases.Include(x => x.Artist).FirstOrDefault(x => x.RoadieId == releaseId);
|
||||
var user = this.DbContext.Users.FirstOrDefault(x => x.RoadieId == userId);
|
||||
if (user.Id == applicationUser.Id)
|
||||
{
|
||||
var ex = new Exception("User cannot self.");
|
||||
this.Logger.LogError(ex);
|
||||
await this.LogAndPublish("Error deleting user.");
|
||||
errors.Add(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
if (release == null)
|
||||
if (user == null)
|
||||
{
|
||||
await this.LogAndPublish($"DeleteRelease Unknown Release [{ releaseId}]", LogLevel.Warning);
|
||||
return new OperationResult<bool>(true, $"Release Not Found [{ releaseId }]");
|
||||
await this.LogAndPublish($"DeleteUser Unknown User [{ userId}]", LogLevel.Warning);
|
||||
return new OperationResult<bool>(true, $"User Not Found [{ userId }]");
|
||||
}
|
||||
await this.ReleaseFactory.Delete(release, doDeleteFiles ?? false);
|
||||
this.DbContext.Users.Remove(user);
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
await this.LogAndPublish("Error deleting release.");
|
||||
await this.LogAndPublish("Error deleting user.");
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
await this.LogAndPublish($"DeleteRelease `{ release }`, By User `{ user}`", LogLevel.Information);
|
||||
await this.LogAndPublish($"DeleteUser `{ user }`, By User `{ user}`", LogLevel.Information);
|
||||
this.CacheManager.Clear();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
|
@ -357,6 +399,86 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleases(ApplicationUser user)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
var missingData = new Dictionary<string, List<string>>();
|
||||
|
||||
foreach (var collection in this.DbContext.Collections.Where(x => x.Status != Statuses.Complete))
|
||||
{
|
||||
var collectionReleases = (from cr in this.DbContext.CollectionReleases
|
||||
where cr.CollectionId == collection.Id
|
||||
select cr);
|
||||
PositionAristRelease[] pars = null;
|
||||
|
||||
try
|
||||
{
|
||||
pars = collection.PositionArtistReleases().ToArray();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
missingData.Add($"CSV Error [{ collection.Name }]", new List<string> { ex.Message });
|
||||
continue;
|
||||
}
|
||||
foreach (var par in pars)
|
||||
{
|
||||
var cr = collectionReleases.FirstOrDefault(x => x.ListNumber == par.Position);
|
||||
if (cr == null)
|
||||
{
|
||||
// If artist is already in result then add missing album to artist, if not then add artist then add missing album
|
||||
if (!missingData.ContainsKey(par.Artist))
|
||||
{
|
||||
missingData.Add(par.Artist, new List<string>());
|
||||
}
|
||||
var r = $"[{ collection.Name }]:[{ par.Release }]";
|
||||
missingData[par.Artist].Add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
return Task.FromResult(new OperationResult<Dictionary<string, List<string>>>
|
||||
{
|
||||
Data = missingData.OrderBy(x => x.Value.Count()).ToDictionary(x => x.Key, x => x.Value),
|
||||
IsSuccess = true,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanAllCollections(ApplicationUser user, bool isReadOnly = false, bool doPurgeFirst = true)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
|
||||
var collections = this.DbContext.Collections.Where(x => x.Status != Statuses.Complete).ToArray();
|
||||
foreach (var collection in collections)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await this.ScanCollection(user, collection.RoadieId, isReadOnly, doPurgeFirst);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
errors.AddRange(result.Errors);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
this.Logger.LogInformation(string.Format("ScanAllCollections, By User `{0}`", user));
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanArtist(ApplicationUser user, Guid artistId, bool isReadOnly = false)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
|
@ -400,87 +522,6 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanAllCollections(ApplicationUser user, bool isReadOnly = false, bool doPurgeFirst = true)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
|
||||
var collections = this.DbContext.Collections.Where(x => x.Status != Statuses.Complete).ToArray();
|
||||
foreach(var collection in collections)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await this.ScanCollection(user, collection.RoadieId, isReadOnly, doPurgeFirst);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
errors.AddRange(result.Errors);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
this.Logger.LogInformation(string.Format("ScanAllCollections, By User `{0}`", user));
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleases(ApplicationUser user)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
var missingData = new Dictionary<string, List<string>>();
|
||||
|
||||
foreach (var collection in this.DbContext.Collections.Where(x => x.Status != Statuses.Complete))
|
||||
{
|
||||
var collectionReleases = (from cr in this.DbContext.CollectionReleases
|
||||
where cr.CollectionId == collection.Id
|
||||
select cr);
|
||||
PositionAristRelease[] pars = null;
|
||||
|
||||
try
|
||||
{
|
||||
pars = collection.PositionArtistReleases().ToArray();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
missingData.Add($"CSV Error [{ collection.Name }]", new List<string>{ ex.Message });
|
||||
continue;
|
||||
}
|
||||
foreach (var par in pars)
|
||||
{
|
||||
var cr = collectionReleases.FirstOrDefault(x => x.ListNumber == par.Position);
|
||||
if (cr == null)
|
||||
{
|
||||
// If artist is already in result then add missing album to artist, if not then add artist then add missing album
|
||||
if(!missingData.ContainsKey(par.Artist))
|
||||
{
|
||||
missingData.Add(par.Artist, new List<string>());
|
||||
}
|
||||
var r = $"[{ collection.Name }]:[{ par.Release }]";
|
||||
missingData[par.Artist].Add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
return Task.FromResult(new OperationResult<Dictionary<string, List<string>>>
|
||||
{
|
||||
Data = missingData.OrderBy(x => x.Value.Count()).ToDictionary(x => x.Key, x => x.Value),
|
||||
IsSuccess = true,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanCollection(ApplicationUser user, Guid collectionId, bool isReadOnly = false, bool doPurgeFirst = true)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
|
@ -508,8 +549,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
var now = DateTime.UtcNow;
|
||||
foreach (var csvRelease in par)
|
||||
{
|
||||
|
||||
{
|
||||
data.Artist artist = null;
|
||||
data.Release release = null;
|
||||
|
||||
|
@ -517,11 +557,11 @@ namespace Roadie.Api.Services
|
|||
var specialSearchName = csvRelease.Artist.ToAlphanumericName();
|
||||
|
||||
var artistResults = (from a in this.DbContext.Artists
|
||||
where (a.Name.Contains(searchName) ||
|
||||
a.SortName.Contains(searchName) ||
|
||||
a.AlternateNames.Contains(searchName) ||
|
||||
a.AlternateNames.Contains(specialSearchName))
|
||||
select a).ToArray();
|
||||
where (a.Name.Contains(searchName) ||
|
||||
a.SortName.Contains(searchName) ||
|
||||
a.AlternateNames.Contains(searchName) ||
|
||||
a.AlternateNames.Contains(specialSearchName))
|
||||
select a).ToArray();
|
||||
if (!artistResults.Any())
|
||||
{
|
||||
this.Logger.LogWarning("Unable To Find Artist [{0}], SearchName [{1}]", csvRelease.Artist, searchName);
|
||||
|
@ -534,13 +574,13 @@ namespace Roadie.Api.Services
|
|||
searchName = csvRelease.Release.NormalizeName().ToLower();
|
||||
specialSearchName = csvRelease.Release.ToAlphanumericName();
|
||||
release = (from r in this.DbContext.Releases
|
||||
where (r.ArtistId == artist.Id)
|
||||
where (r.Title.Contains(searchName) ||
|
||||
r.AlternateNames.Contains(searchName) ||
|
||||
r.AlternateNames.Contains(specialSearchName))
|
||||
select r
|
||||
where (r.ArtistId == artist.Id)
|
||||
where (r.Title.Contains(searchName) ||
|
||||
r.AlternateNames.Contains(searchName) ||
|
||||
r.AlternateNames.Contains(specialSearchName))
|
||||
select r
|
||||
).FirstOrDefault();
|
||||
if(release != null)
|
||||
if (release != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -550,9 +590,9 @@ namespace Roadie.Api.Services
|
|||
this.Logger.LogWarning("Unable To Find Release [{0}], SearchName [{1}]", csvRelease.Release, searchName);
|
||||
csvRelease.Status = Library.Enums.Statuses.Missing;
|
||||
continue;
|
||||
}
|
||||
var isInCollection = this.DbContext.CollectionReleases.FirstOrDefault(x => x.CollectionId == collection.Id &&
|
||||
x.ListNumber == csvRelease.Position &&
|
||||
}
|
||||
var isInCollection = this.DbContext.CollectionReleases.FirstOrDefault(x => x.CollectionId == collection.Id &&
|
||||
x.ListNumber == csvRelease.Position &&
|
||||
x.ReleaseId == release.Id);
|
||||
// Found in Database but not in collection add to Collection
|
||||
if (isInCollection == null)
|
||||
|
@ -656,7 +696,7 @@ namespace Roadie.Api.Services
|
|||
errors.Add(ex);
|
||||
}
|
||||
sw.Stop();
|
||||
|
||||
|
||||
this.DbContext.ScanHistories.Add(new data.ScanHistory
|
||||
{
|
||||
UserId = user.Id,
|
||||
|
|
|
@ -184,7 +184,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
var onlyWithReleases = onlyIncludeWithReleases ?? true;
|
||||
var isEqualFilter = false;
|
||||
if(!string.IsNullOrEmpty(request.FilterValue))
|
||||
if (!string.IsNullOrEmpty(request.FilterValue))
|
||||
{
|
||||
var filter = request.FilterValue;
|
||||
// if filter string is wrapped in quotes then is an exact not like search, e.g. "Diana Ross" should not return "Diana Ross & The Supremes"
|
||||
|
@ -199,9 +199,9 @@ namespace Roadie.Api.Services
|
|||
where (!onlyWithReleases || a.ReleaseCount > 0)
|
||||
where (request.FilterToArtistId == null || a.RoadieId == request.FilterToArtistId)
|
||||
where (request.FilterMinimumRating == null || a.Rating >= request.FilterMinimumRating.Value)
|
||||
where (request.FilterValue == "" || (a.Name.Contains(request.FilterValue) ||
|
||||
a.SortName.Contains(request.FilterValue) ||
|
||||
a.AlternateNames.Contains(request.FilterValue) ||
|
||||
where (request.FilterValue == "" || (a.Name.Contains(request.FilterValue) ||
|
||||
a.SortName.Contains(request.FilterValue) ||
|
||||
a.AlternateNames.Contains(request.FilterValue) ||
|
||||
a.AlternateNames.Contains(normalizedFilterValue)))
|
||||
where (!isEqualFilter || (a.Name.Equals(request.FilterValue) ||
|
||||
a.SortName.Equals(request.FilterValue) ||
|
||||
|
@ -276,7 +276,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
}
|
||||
sw.Stop();
|
||||
if(!string.IsNullOrEmpty(request.Filter) && rowCount == 0)
|
||||
if (!string.IsNullOrEmpty(request.Filter) && rowCount == 0)
|
||||
{
|
||||
// Create request for no artist found
|
||||
var req = new data.Request
|
||||
|
@ -297,6 +297,57 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> MergeArtists(User user, Guid artistToMergeId, Guid artistToMergeIntoId)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var errors = new List<Exception>();
|
||||
var artistToMerge = this.DbContext.Artists
|
||||
.Include(x => x.Genres)
|
||||
.Include("Genres.Genre")
|
||||
.FirstOrDefault(x => x.RoadieId == artistToMergeId);
|
||||
if (artistToMerge == null)
|
||||
{
|
||||
this.Logger.LogWarning("MergeArtists Unknown Artist [{0}]", artistToMergeId);
|
||||
return new OperationResult<bool>(true, string.Format("Artist Not Found [{0}]", artistToMergeId));
|
||||
}
|
||||
var mergeIntoArtist = this.DbContext.Artists
|
||||
.Include(x => x.Genres)
|
||||
.Include("Genres.Genre")
|
||||
.FirstOrDefault(x => x.RoadieId == artistToMergeIntoId);
|
||||
if (mergeIntoArtist == null)
|
||||
{
|
||||
this.Logger.LogWarning("MergeArtists Unknown Artist [{0}]", artistToMergeIntoId);
|
||||
return new OperationResult<bool>(true, string.Format("Artist Not Found [{0}]", artistToMergeIntoId));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var result = await this.ArtistFactory.MergeArtists(artistToMerge, mergeIntoArtist, true);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
this.CacheManager.ClearRegion(artistToMerge.CacheRegion);
|
||||
this.CacheManager.ClearRegion(mergeIntoArtist.CacheRegion);
|
||||
this.Logger.LogInformation("MergeArtists `{0}` => `{1}`, By User `{2}`", artistToMerge, mergeIntoArtist, user);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanArtistReleasesFolders(Guid artistId, string destinationFolder, bool doJustInfo)
|
||||
{
|
||||
SimpleContract.Requires<ArgumentOutOfRangeException>(artistId != Guid.Empty, "Invalid ArtistId");
|
||||
|
@ -460,7 +511,7 @@ namespace Roadie.Api.Services
|
|||
didChangeThumbnail = true;
|
||||
}
|
||||
|
||||
if(model.NewSecondaryImagesData != null && model.NewSecondaryImagesData.Any())
|
||||
if (model.NewSecondaryImagesData != null && model.NewSecondaryImagesData.Any())
|
||||
{
|
||||
// Additional images to add to artist
|
||||
var looper = 0;
|
||||
|
@ -473,7 +524,7 @@ namespace Roadie.Api.Services
|
|||
artistSecondaryImage = ImageHelper.ConvertToJpegFormat(artistSecondaryImage);
|
||||
|
||||
var aristImageFilename = Path.Combine(newArtistFolder, string.Format(ImageHelper.ArtistSecondaryImageFilename, looper.ToString("00")));
|
||||
while(File.Exists(aristImageFilename))
|
||||
while (File.Exists(aristImageFilename))
|
||||
{
|
||||
looper++;
|
||||
aristImageFilename = Path.Combine(newArtistFolder, string.Format(ImageHelper.ArtistSecondaryImageFilename, looper.ToString("00")));
|
||||
|
@ -600,59 +651,6 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> MergeArtists(User user, Guid artistToMergeId, Guid artistToMergeIntoId)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var errors = new List<Exception>();
|
||||
var artistToMerge = this.DbContext.Artists
|
||||
.Include(x => x.Genres)
|
||||
.Include("Genres.Genre")
|
||||
.FirstOrDefault(x => x.RoadieId == artistToMergeId);
|
||||
if (artistToMerge == null)
|
||||
{
|
||||
this.Logger.LogWarning("MergeArtists Unknown Artist [{0}]", artistToMergeId);
|
||||
return new OperationResult<bool>(true, string.Format("Artist Not Found [{0}]", artistToMergeId));
|
||||
}
|
||||
var mergeIntoArtist = this.DbContext.Artists
|
||||
.Include(x => x.Genres)
|
||||
.Include("Genres.Genre")
|
||||
.FirstOrDefault(x => x.RoadieId == artistToMergeIntoId);
|
||||
if (mergeIntoArtist == null)
|
||||
{
|
||||
this.Logger.LogWarning("MergeArtists Unknown Artist [{0}]", artistToMergeIntoId);
|
||||
return new OperationResult<bool>(true, string.Format("Artist Not Found [{0}]", artistToMergeIntoId));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var result = await this.ArtistFactory.MergeArtists(artistToMerge, mergeIntoArtist, true);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
this.CacheManager.ClearRegion(artistToMerge.CacheRegion);
|
||||
this.CacheManager.ClearRegion(mergeIntoArtist.CacheRegion);
|
||||
this.Logger.LogInformation("MergeArtists `{0}` => `{1}`, By User `{2}`", artistToMerge, mergeIntoArtist, user);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async Task<OperationResult<Library.Models.Image>> UploadArtistImage(User user, Guid id, IFormFile file)
|
||||
{
|
||||
var bytes = new byte[0];
|
||||
|
@ -769,7 +767,6 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
tsw.Stop();
|
||||
timings.Add("stats", tsw.ElapsedMilliseconds);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
case BookmarkType.Artist:
|
||||
var artist = this.DbContext.Artists.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
||||
if(artist == null)
|
||||
if (artist == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ using Roadie.Library.Utility;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -74,6 +73,120 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Collection>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
|
||||
var cacheKey = string.Format("urn:collection_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
|
||||
var result = await this.CacheManager.GetAsync<OperationResult<Collection>>(cacheKey, async () =>
|
||||
{
|
||||
return await this.CollectionByIdAction(id, includes);
|
||||
}, data.Artist.CacheRegionUrn(id));
|
||||
sw.Stop();
|
||||
if (result?.Data != null && roadieUser != null)
|
||||
{
|
||||
var userBookmarkResult = await this.BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Collection);
|
||||
if (userBookmarkResult.IsSuccess)
|
||||
{
|
||||
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Text == result.Data.Id.ToString()) != null;
|
||||
}
|
||||
}
|
||||
return new OperationResult<Collection>(result.Messages)
|
||||
{
|
||||
Data = result?.Data,
|
||||
IsNotFoundResult = result?.IsNotFoundResult ?? false,
|
||||
Errors = result?.Errors,
|
||||
IsSuccess = result?.IsSuccess ?? false,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteCollection(User user, Guid id)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var collection = this.DbContext.Collections.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (collection == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Collection Not Found [{ id }]");
|
||||
}
|
||||
if (!user.IsEditor)
|
||||
{
|
||||
this.Logger.LogWarning($"DeleteCollection: Access Denied: `{ collection }`, By User `{user }`");
|
||||
return new OperationResult<bool>("Access Denied");
|
||||
}
|
||||
try
|
||||
{
|
||||
this.DbContext.Collections.Remove(collection);
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
sw.Stop();
|
||||
this.Logger.LogInformation($"DeleteCollection `{ collection }`, By User `{user }`");
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public Task<Library.Models.Pagination.PagedResult<CollectionList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, Guid? releaseId = null, Guid? artistId = null)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
IQueryable<data.Collection> collections = null;
|
||||
if (artistId.HasValue)
|
||||
{
|
||||
var sql = @"select DISTINCT c.*
|
||||
from `collectionrelease` cr
|
||||
join `collection` c on c.id = cr.collectionId
|
||||
join `release` r on r.id = cr.releaseId
|
||||
join `artist` a on r.artistId = a.id
|
||||
where a.roadieId = {0}";
|
||||
|
||||
collections = this.DbContext.Collections.FromSql(sql, artistId);
|
||||
}
|
||||
else if (releaseId.HasValue)
|
||||
{
|
||||
var sql = @"select DISTINCT c.*
|
||||
from `collectionrelease` cr
|
||||
join `collection` c on c.id = cr.collectionId
|
||||
join `release` r on r.id = cr.releaseId
|
||||
where r.roadieId = {0}";
|
||||
|
||||
collections = this.DbContext.Collections.FromSql(sql, releaseId);
|
||||
}
|
||||
else
|
||||
{
|
||||
collections = this.DbContext.Collections;
|
||||
}
|
||||
var result = (from c in collections
|
||||
where (request.FilterValue.Length == 0 || (request.FilterValue.Length > 0 && c.Name.Contains(request.Filter)))
|
||||
select CollectionList.FromDataCollection(c, (from crc in this.DbContext.CollectionReleases
|
||||
where crc.CollectionId == c.Id
|
||||
select crc.Id).Count(), this.MakeCollectionThumbnailImage(c.RoadieId)));
|
||||
var sortBy = string.IsNullOrEmpty(request.Sort) ? request.OrderValue(new Dictionary<string, string> { { "Collection.Text", "ASC" } }) : request.OrderValue(null);
|
||||
var rowCount = result.Count();
|
||||
var rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
|
||||
sw.Stop();
|
||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<CollectionList>
|
||||
{
|
||||
TotalCount = rowCount,
|
||||
CurrentPage = request.PageValue,
|
||||
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Rows = rows
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates (or Adds) Collection
|
||||
/// </summary>
|
||||
|
@ -88,7 +201,7 @@ namespace Roadie.Api.Services
|
|||
|
||||
data.Collection collection = new data.Collection();
|
||||
|
||||
if(!isNew)
|
||||
if (!isNew)
|
||||
{
|
||||
collection = this.DbContext.Collections.FirstOrDefault(x => x.RoadieId == model.Id);
|
||||
if (collection == null)
|
||||
|
@ -147,121 +260,6 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteCollection(User user, Guid id)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var collection = this.DbContext.Collections.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (collection == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Collection Not Found [{ id }]");
|
||||
}
|
||||
if(!user.IsEditor)
|
||||
{
|
||||
this.Logger.LogWarning($"DeleteCollection: Access Denied: `{ collection }`, By User `{user }`");
|
||||
return new OperationResult<bool>("Access Denied");
|
||||
}
|
||||
try
|
||||
{
|
||||
this.DbContext.Collections.Remove(collection);
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
sw.Stop();
|
||||
this.Logger.LogInformation($"DeleteCollection `{ collection }`, By User `{user }`");
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public async Task<OperationResult<Collection>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
|
||||
var cacheKey = string.Format("urn:collection_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
|
||||
var result = await this.CacheManager.GetAsync<OperationResult<Collection>>(cacheKey, async () =>
|
||||
{
|
||||
return await this.CollectionByIdAction(id, includes);
|
||||
}, data.Artist.CacheRegionUrn(id));
|
||||
sw.Stop();
|
||||
if (result?.Data != null && roadieUser != null)
|
||||
{
|
||||
var userBookmarkResult = await this.BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Collection);
|
||||
if (userBookmarkResult.IsSuccess)
|
||||
{
|
||||
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Text == result.Data.Id.ToString()) != null;
|
||||
}
|
||||
}
|
||||
return new OperationResult<Collection>(result.Messages)
|
||||
{
|
||||
Data = result?.Data,
|
||||
IsNotFoundResult = result?.IsNotFoundResult ?? false,
|
||||
Errors = result?.Errors,
|
||||
IsSuccess = result?.IsSuccess ?? false,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public Task<Library.Models.Pagination.PagedResult<CollectionList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, Guid? releaseId = null, Guid? artistId = null)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
IQueryable<data.Collection> collections = null;
|
||||
if (artistId.HasValue)
|
||||
{
|
||||
var sql = @"select DISTINCT c.*
|
||||
from `collectionrelease` cr
|
||||
join `collection` c on c.id = cr.collectionId
|
||||
join `release` r on r.id = cr.releaseId
|
||||
join `artist` a on r.artistId = a.id
|
||||
where a.roadieId = {0}";
|
||||
|
||||
collections = this.DbContext.Collections.FromSql(sql, artistId);
|
||||
}
|
||||
else if (releaseId.HasValue)
|
||||
{
|
||||
var sql = @"select DISTINCT c.*
|
||||
from `collectionrelease` cr
|
||||
join `collection` c on c.id = cr.collectionId
|
||||
join `release` r on r.id = cr.releaseId
|
||||
where r.roadieId = {0}";
|
||||
|
||||
collections = this.DbContext.Collections.FromSql(sql, releaseId);
|
||||
}
|
||||
else
|
||||
{
|
||||
collections = this.DbContext.Collections;
|
||||
}
|
||||
var result = (from c in collections
|
||||
where (request.FilterValue.Length == 0 || (request.FilterValue.Length > 0 && c.Name.Contains(request.Filter)))
|
||||
select CollectionList.FromDataCollection(c, (from crc in this.DbContext.CollectionReleases
|
||||
where crc.CollectionId == c.Id
|
||||
select crc.Id).Count(), this.MakeCollectionThumbnailImage(c.RoadieId)));
|
||||
var sortBy = string.IsNullOrEmpty(request.Sort) ? request.OrderValue(new Dictionary<string, string> { { "Collection.Text", "ASC" } }) : request.OrderValue(null);
|
||||
var rowCount = result.Count();
|
||||
var rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
|
||||
sw.Stop();
|
||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<CollectionList>
|
||||
{
|
||||
TotalCount = rowCount,
|
||||
CurrentPage = request.PageValue,
|
||||
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Rows = rows
|
||||
});
|
||||
}
|
||||
|
||||
private Task<OperationResult<Collection>> CollectionByIdAction(Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Roadie.Api.Services
|
|||
scheme = "https";
|
||||
}
|
||||
var host = urlHelper.ActionContext.HttpContext.Request.Host;
|
||||
if(!string.IsNullOrEmpty(configuration.BehindProxyHost))
|
||||
if (!string.IsNullOrEmpty(configuration.BehindProxyHost))
|
||||
{
|
||||
host = new Microsoft.AspNetCore.Http.HostString(configuration.BehindProxyHost);
|
||||
}
|
||||
|
|
|
@ -11,16 +11,20 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
Task<OperationResult<bool>> DeleteArtist(ApplicationUser user, Guid artistId);
|
||||
|
||||
Task<OperationResult<bool>> DeleteArtistSecondaryImage(ApplicationUser user, Guid artistId, int index);
|
||||
|
||||
Task<OperationResult<bool>> DeleteArtistReleases(ApplicationUser user, Guid artistId, bool doDeleteFiles = false);
|
||||
|
||||
Task<OperationResult<bool>> DeleteArtistSecondaryImage(ApplicationUser user, Guid artistId, int index);
|
||||
|
||||
Task<OperationResult<bool>> DeleteRelease(ApplicationUser user, Guid releaseId, bool? doDeleteFiles);
|
||||
|
||||
Task<OperationResult<bool>> DeleteTrack(ApplicationUser user, Guid trackId, bool? doDeleteFile);
|
||||
|
||||
Task<OperationResult<bool>> DeleteUser(ApplicationUser applicationUser, Guid id);
|
||||
|
||||
Task<OperationResult<bool>> DoInitialSetup(ApplicationUser user, UserManager<ApplicationUser> userManager);
|
||||
|
||||
Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleases(ApplicationUser user);
|
||||
|
||||
Task<OperationResult<bool>> ScanAllCollections(ApplicationUser user, bool isReadOnly = false, bool doPurgeFirst = true);
|
||||
|
||||
Task<OperationResult<bool>> ScanArtist(ApplicationUser user, Guid artistId, bool isReadOnly = false);
|
||||
|
@ -32,7 +36,5 @@ namespace Roadie.Api.Services
|
|||
Task<OperationResult<bool>> ScanLibraryFolder(ApplicationUser user, bool isReadOnly = false);
|
||||
|
||||
Task<OperationResult<bool>> ScanRelease(ApplicationUser user, Guid releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false);
|
||||
|
||||
Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleases(ApplicationUser user);
|
||||
}
|
||||
}
|
|
@ -15,12 +15,12 @@ namespace Roadie.Api.Services
|
|||
|
||||
Task<PagedResult<ArtistList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, bool? onlyIncludeWithReleases = true);
|
||||
|
||||
Task<OperationResult<bool>> MergeArtists(User user, Guid artistToMergeId, Guid artistToMergeIntoId);
|
||||
|
||||
Task<OperationResult<Library.Models.Image>> SetReleaseImageByUrl(User user, Guid id, string imageUrl);
|
||||
|
||||
Task<OperationResult<bool>> UpdateArtist(User user, Artist artist);
|
||||
|
||||
Task<OperationResult<Library.Models.Image>> UploadArtistImage(User user, Guid id, IFormFile file);
|
||||
|
||||
Task<OperationResult<bool>> MergeArtists(User user, Guid artistToMergeId, Guid artistToMergeIntoId);
|
||||
}
|
||||
}
|
|
@ -12,12 +12,12 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
OperationResult<Collection> Add(User roadieUser);
|
||||
|
||||
Task<OperationResult<bool>> UpdateCollection(User roadieUser, Collection collection);
|
||||
Task<OperationResult<Collection>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null);
|
||||
|
||||
Task<OperationResult<bool>> DeleteCollection(User user, Guid id);
|
||||
|
||||
Task<OperationResult<Collection>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null);
|
||||
|
||||
Task<PagedResult<CollectionList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, Guid? releaseId = null, Guid? artistId = null);
|
||||
|
||||
Task<OperationResult<bool>> UpdateCollection(User roadieUser, Collection collection);
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ namespace Roadie.Api.Services
|
|||
public interface IImageService
|
||||
{
|
||||
Task<FileOperationResult<Library.Models.Image>> ArtistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<Library.Models.Image>> ArtistSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<Library.Models.Image>> ById(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
@ -26,6 +27,7 @@ namespace Roadie.Api.Services
|
|||
Task<FileOperationResult<Library.Models.Image>> PlaylistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<Library.Models.Image>> ReleaseImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<Library.Models.Image>> ReleaseSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<OperationResult<IEnumerable<ImageSearchResult>>> Search(string query, int resultsCount = 10);
|
||||
|
|
|
@ -15,6 +15,8 @@ namespace Roadie.Api.Services
|
|||
|
||||
Task<PagedResult<ReleaseList>> List(User user, PagedRequest request, bool? doRandomize = false, IEnumerable<string> includes = null);
|
||||
|
||||
Task<OperationResult<bool>> MergeReleases(User user, Guid releaseToMergeId, Guid releaseToMergeIntoId, bool addAsMedia);
|
||||
|
||||
Task<FileOperationResult<byte[]>> ReleaseZipped(User roadieUser, Guid id);
|
||||
|
||||
Task<OperationResult<Library.Models.Image>> SetReleaseImageByUrl(User user, Guid id, string imageUrl);
|
||||
|
@ -22,7 +24,5 @@ namespace Roadie.Api.Services
|
|||
Task<OperationResult<bool>> UpdateRelease(User user, Release release);
|
||||
|
||||
Task<OperationResult<Library.Models.Image>> UploadReleaseImage(User user, Guid id, IFormFile file);
|
||||
|
||||
Task<OperationResult<bool>> MergeReleases(User user, Guid releaseToMergeId, Guid releaseToMergeIntoId, bool addAsMedia);
|
||||
}
|
||||
}
|
|
@ -14,10 +14,10 @@ namespace Roadie.Api.Services
|
|||
|
||||
Task<Library.Models.Pagination.PagedResult<TrackList>> List(PagedRequest request, User roadieUser, bool? doRandomize = false, Guid? releaseId = null);
|
||||
|
||||
Task<OperationResult<bool>> UpdateTrack(User user, Track track);
|
||||
|
||||
OperationResult<Track> StreamCheckAndInfo(User roadieUser, Guid id);
|
||||
|
||||
Task<OperationResult<TrackStreamInfo>> TrackStreamInfo(Guid trackId, long beginBytes, long endBytes, User roadieUser);
|
||||
|
||||
Task<OperationResult<bool>> UpdateTrack(User user, Track track);
|
||||
}
|
||||
}
|
|
@ -201,7 +201,7 @@ namespace Roadie.Api.Services
|
|||
etag: etag);
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<Image>> ReleaseSecondaryImage(Guid id,int imageId, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
public async Task<FileOperationResult<Image>> ReleaseSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return await this.GetImageFileOperation(type: $"ReleaseSecondaryThumbnail-{imageId}",
|
||||
regionUrn: data.Release.CacheRegionUrn(id),
|
||||
|
@ -298,7 +298,7 @@ namespace Roadie.Api.Services
|
|||
else
|
||||
{
|
||||
var artistImages = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), Library.Enums.ImageType.Artist);
|
||||
if(artistImages.Any())
|
||||
if (artistImages.Any())
|
||||
{
|
||||
imageBytes = File.ReadAllBytes(artistImages.First().FullName);
|
||||
}
|
||||
|
@ -328,6 +328,53 @@ namespace Roadie.Api.Services
|
|||
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
|
||||
}
|
||||
|
||||
private Task<FileOperationResult<Image>> ArtistSecondaryImageAction(Guid id, int imageId, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var artist = this.GetArtist(id);
|
||||
if (artist == null)
|
||||
{
|
||||
return Task.FromResult(new FileOperationResult<Image>(true, string.Format("Release Not Found [{0}]", id)));
|
||||
}
|
||||
byte[] imageBytes = null;
|
||||
string artistFolder = null;
|
||||
try
|
||||
{
|
||||
// See if cover art file exists in release folder
|
||||
artistFolder = artist.ArtistFileFolder(this.Configuration, this.Configuration.LibraryFolder);
|
||||
if (!Directory.Exists(artistFolder))
|
||||
{
|
||||
this.Logger.LogWarning($"Artist Folder [{ artistFolder }], Not Found For Artist `{ artist }`");
|
||||
}
|
||||
else
|
||||
{
|
||||
var artistSecondaryImages = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), Library.Enums.ImageType.ArtistSecondary).ToArray();
|
||||
if (artistSecondaryImages.Length >= imageId && artistSecondaryImages[imageId] != null)
|
||||
{
|
||||
imageBytes = File.ReadAllBytes(artistSecondaryImages[imageId].FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex, $"Error Reading Artist Folder [{ artistFolder }] For Artist `{ artist }`");
|
||||
}
|
||||
var image = new data.Image
|
||||
{
|
||||
Bytes = imageBytes,
|
||||
CreatedDate = artist.CreatedDate,
|
||||
LastUpdated = artist.LastUpdated
|
||||
};
|
||||
return Task.FromResult(GenerateFileOperationResult(id, image, etag));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError($"Error fetching Release Thumbnail [{ id }]", ex);
|
||||
}
|
||||
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
|
||||
}
|
||||
|
||||
private Task<FileOperationResult<Image>> CollectionImageAction(Guid id, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
try
|
||||
|
@ -527,7 +574,7 @@ namespace Roadie.Api.Services
|
|||
else
|
||||
{
|
||||
var releaseCoverFiles = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(releaseFolder), Library.Enums.ImageType.Release);
|
||||
if(releaseCoverFiles.Any())
|
||||
if (releaseCoverFiles.Any())
|
||||
{
|
||||
imageBytes = File.ReadAllBytes(releaseCoverFiles.First().FullName);
|
||||
}
|
||||
|
@ -588,10 +635,10 @@ namespace Roadie.Api.Services
|
|||
else
|
||||
{
|
||||
var releaseSecondaryImages = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(releaseFolder), Library.Enums.ImageType.ReleaseSecondary).ToArray();
|
||||
if(releaseSecondaryImages.Length >= imageId && releaseSecondaryImages[imageId] != null)
|
||||
if (releaseSecondaryImages.Length >= imageId && releaseSecondaryImages[imageId] != null)
|
||||
{
|
||||
imageBytes = File.ReadAllBytes(releaseSecondaryImages[imageId].FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -614,54 +661,6 @@ namespace Roadie.Api.Services
|
|||
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
|
||||
}
|
||||
|
||||
private Task<FileOperationResult<Image>> ArtistSecondaryImageAction(Guid id, int imageId, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var artist = this.GetArtist(id);
|
||||
if (artist == null)
|
||||
{
|
||||
return Task.FromResult(new FileOperationResult<Image>(true, string.Format("Release Not Found [{0}]", id)));
|
||||
}
|
||||
byte[] imageBytes = null;
|
||||
string artistFolder = null;
|
||||
try
|
||||
{
|
||||
// See if cover art file exists in release folder
|
||||
artistFolder = artist.ArtistFileFolder(this.Configuration, this.Configuration.LibraryFolder);
|
||||
if (!Directory.Exists(artistFolder))
|
||||
{
|
||||
this.Logger.LogWarning($"Artist Folder [{ artistFolder }], Not Found For Artist `{ artist }`");
|
||||
}
|
||||
else
|
||||
{
|
||||
var artistSecondaryImages = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), Library.Enums.ImageType.ArtistSecondary).ToArray();
|
||||
if (artistSecondaryImages.Length >= imageId && artistSecondaryImages[imageId] != null)
|
||||
{
|
||||
imageBytes = File.ReadAllBytes(artistSecondaryImages[imageId].FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex, $"Error Reading Artist Folder [{ artistFolder }] For Artist `{ artist }`");
|
||||
}
|
||||
var image = new data.Image
|
||||
{
|
||||
Bytes = imageBytes,
|
||||
CreatedDate = artist.CreatedDate,
|
||||
LastUpdated = artist.LastUpdated
|
||||
};
|
||||
return Task.FromResult(GenerateFileOperationResult(id, image, etag));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError($"Error fetching Release Thumbnail [{ id }]", ex);
|
||||
}
|
||||
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
|
||||
}
|
||||
|
||||
|
||||
private async Task<FileOperationResult<Image>> TrackImageAction(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -138,49 +138,6 @@ namespace Roadie.Api.Services
|
|||
return await this.SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
|
||||
}
|
||||
|
||||
private async Task<OperationResult<Library.Models.Image>> SaveImageBytes(User user, Guid id, byte[] imageBytes)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var label = this.DbContext.Labels.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (label == null)
|
||||
{
|
||||
return new OperationResult<Library.Models.Image>(true, string.Format("Label Not Found [{0}]", id));
|
||||
}
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
label.Thumbnail = imageBytes;
|
||||
if (label.Thumbnail != null)
|
||||
{
|
||||
// Ensure is jpeg first
|
||||
label.Thumbnail = ImageHelper.ConvertToJpegFormat(label.Thumbnail);
|
||||
|
||||
// Resize to store in database as thumbnail
|
||||
label.Thumbnail = ImageHelper.ResizeImage(label.Thumbnail, this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height);
|
||||
}
|
||||
label.LastUpdated = now;
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
this.CacheManager.ClearRegion(label.CacheRegion);
|
||||
this.Logger.LogInformation($"UploadLabelImage `{ label }` By User `{ user }`");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<Library.Models.Image>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = base.MakeThumbnailImage(id, "label", this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height, true),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdateLabel(User user, Label model)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
|
@ -304,5 +261,48 @@ namespace Roadie.Api.Services
|
|||
OperationTime = sw.ElapsedMilliseconds
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<OperationResult<Library.Models.Image>> SaveImageBytes(User user, Guid id, byte[] imageBytes)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var label = this.DbContext.Labels.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (label == null)
|
||||
{
|
||||
return new OperationResult<Library.Models.Image>(true, string.Format("Label Not Found [{0}]", id));
|
||||
}
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
label.Thumbnail = imageBytes;
|
||||
if (label.Thumbnail != null)
|
||||
{
|
||||
// Ensure is jpeg first
|
||||
label.Thumbnail = ImageHelper.ConvertToJpegFormat(label.Thumbnail);
|
||||
|
||||
// Resize to store in database as thumbnail
|
||||
label.Thumbnail = ImageHelper.ResizeImage(label.Thumbnail, this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height);
|
||||
}
|
||||
label.LastUpdated = now;
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
this.CacheManager.ClearRegion(label.CacheRegion);
|
||||
this.Logger.LogInformation($"UploadLabelImage `{ label }` By User `{ user }`");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<Library.Models.Image>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = base.MakeThumbnailImage(id, "label", this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height, true),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -168,7 +168,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex, $"CreatePlayActivity RoadieUser `{ roadieUser }` StreamInfo `{ streamInfo }`");
|
||||
this.Logger.LogError(ex, $"CreatePlayActivity RoadieUser `{ roadieUser }` StreamInfo `{ streamInfo }`");
|
||||
}
|
||||
return new OperationResult<PlayActivityList>();
|
||||
}
|
||||
|
|
|
@ -63,113 +63,6 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdatePlaylistTracks(User user, PlaylistTrackModifyRequest request)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var playlist = this.DbContext.Playlists.Include(x => x.Tracks).FirstOrDefault(x => x.RoadieId == request.Id);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", request.Id));
|
||||
}
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
playlist.Tracks.Clear();
|
||||
|
||||
var tracks = (from t in this.DbContext.Tracks
|
||||
join plt in request.Tracks on t.RoadieId equals plt.Track.Id
|
||||
select t).ToArray();
|
||||
foreach(var newPlaylistTrack in request.Tracks.OrderBy(x => x.ListNumber))
|
||||
{
|
||||
var track = tracks.FirstOrDefault(x => x.RoadieId == newPlaylistTrack.Track.Id);
|
||||
playlist.Tracks.Add(new data.PlaylistTrack
|
||||
{
|
||||
ListNumber = newPlaylistTrack.ListNumber,
|
||||
PlayListId = playlist.Id,
|
||||
CreatedDate = now,
|
||||
TrackId = track.Id
|
||||
});
|
||||
}
|
||||
playlist.LastUpdated = now;
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
|
||||
// await base.UpdatePlaylistCounts(playlist.Id, now);
|
||||
|
||||
this.Logger.LogInformation($"UpdatePlaylistTracks `{ playlist }` By User `{ user }`");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdatePlaylist(User user, Playlist model)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var playlist = this.DbContext.Playlists.FirstOrDefault(x => x.RoadieId == model.Id);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", model.Id));
|
||||
}
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
playlist.AlternateNames = model.AlternateNamesList.ToDelimitedList();
|
||||
playlist.Description = model.Description;
|
||||
playlist.IsLocked = model.IsLocked;
|
||||
playlist.IsPublic = model.IsPublic;
|
||||
playlist.Name = model.Name;
|
||||
playlist.Status = SafeParser.ToEnum<Statuses>(model.Status);
|
||||
playlist.Tags = model.TagsList.ToDelimitedList();
|
||||
playlist.URLs = model.URLsList.ToDelimitedList();
|
||||
|
||||
var playlistImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
|
||||
if (playlistImage != null)
|
||||
{
|
||||
// Ensure is jpeg first
|
||||
playlist.Thumbnail = ImageHelper.ConvertToJpegFormat(playlistImage);
|
||||
|
||||
// Resize to store in database as thumbnail
|
||||
playlist.Thumbnail = ImageHelper.ResizeImage(playlist.Thumbnail, this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height);
|
||||
}
|
||||
playlist.LastUpdated = now;
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
|
||||
this.CacheManager.ClearRegion(playlist.CacheRegion);
|
||||
this.Logger.LogInformation($"UpdatePlaylist `{ playlist }` By User `{ user }`");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public async Task<OperationResult<bool>> AddTracksToPlaylist(data.Playlist playlist, IEnumerable<Guid> trackIds)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
|
@ -362,6 +255,112 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdatePlaylist(User user, Playlist model)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var playlist = this.DbContext.Playlists.FirstOrDefault(x => x.RoadieId == model.Id);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", model.Id));
|
||||
}
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
playlist.AlternateNames = model.AlternateNamesList.ToDelimitedList();
|
||||
playlist.Description = model.Description;
|
||||
playlist.IsLocked = model.IsLocked;
|
||||
playlist.IsPublic = model.IsPublic;
|
||||
playlist.Name = model.Name;
|
||||
playlist.Status = SafeParser.ToEnum<Statuses>(model.Status);
|
||||
playlist.Tags = model.TagsList.ToDelimitedList();
|
||||
playlist.URLs = model.URLsList.ToDelimitedList();
|
||||
|
||||
var playlistImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
|
||||
if (playlistImage != null)
|
||||
{
|
||||
// Ensure is jpeg first
|
||||
playlist.Thumbnail = ImageHelper.ConvertToJpegFormat(playlistImage);
|
||||
|
||||
// Resize to store in database as thumbnail
|
||||
playlist.Thumbnail = ImageHelper.ResizeImage(playlist.Thumbnail, this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height);
|
||||
}
|
||||
playlist.LastUpdated = now;
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
|
||||
this.CacheManager.ClearRegion(playlist.CacheRegion);
|
||||
this.Logger.LogInformation($"UpdatePlaylist `{ playlist }` By User `{ user }`");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdatePlaylistTracks(User user, PlaylistTrackModifyRequest request)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var playlist = this.DbContext.Playlists.Include(x => x.Tracks).FirstOrDefault(x => x.RoadieId == request.Id);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", request.Id));
|
||||
}
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
playlist.Tracks.Clear();
|
||||
|
||||
var tracks = (from t in this.DbContext.Tracks
|
||||
join plt in request.Tracks on t.RoadieId equals plt.Track.Id
|
||||
select t).ToArray();
|
||||
foreach (var newPlaylistTrack in request.Tracks.OrderBy(x => x.ListNumber))
|
||||
{
|
||||
var track = tracks.FirstOrDefault(x => x.RoadieId == newPlaylistTrack.Track.Id);
|
||||
playlist.Tracks.Add(new data.PlaylistTrack
|
||||
{
|
||||
ListNumber = newPlaylistTrack.ListNumber,
|
||||
PlayListId = playlist.Id,
|
||||
CreatedDate = now,
|
||||
TrackId = track.Id
|
||||
});
|
||||
}
|
||||
playlist.LastUpdated = now;
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
|
||||
// await base.UpdatePlaylistCounts(playlist.Id, now);
|
||||
|
||||
this.Logger.LogInformation($"UpdatePlaylistTracks `{ playlist }` By User `{ user }`");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
private Task<OperationResult<Playlist>> PlaylistByIdAction(Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
|
|
@ -245,8 +245,8 @@ namespace Roadie.Api.Services
|
|||
where (!isFilteredToGenre || genreReleaseIds.Contains(r.Id))
|
||||
where (request.FilterFromYear == null || r.ReleaseDate != null && r.ReleaseDate.Value.Year <= request.FilterFromYear)
|
||||
where (request.FilterToYear == null || r.ReleaseDate != null && r.ReleaseDate.Value.Year >= request.FilterToYear)
|
||||
where (request.FilterValue == "" || (r.Title.Contains(request.FilterValue) ||
|
||||
r.AlternateNames.Contains(request.FilterValue) ||
|
||||
where (request.FilterValue == "" || (r.Title.Contains(request.FilterValue) ||
|
||||
r.AlternateNames.Contains(request.FilterValue) ||
|
||||
r.AlternateNames.Contains(normalizedFilterValue)))
|
||||
where (!isEqualFilter || (r.Title.Equals(request.FilterValue) ||
|
||||
r.AlternateNames.Equals(request.FilterValue) ||
|
||||
|
@ -838,7 +838,7 @@ namespace Roadie.Api.Services
|
|||
var artistFolder = release.Artist.ArtistFileFolder(this.Configuration, this.Configuration.LibraryFolder);
|
||||
var releaseFolder = release.ReleaseFileFolder(artistFolder);
|
||||
var releaseImagesInFolder = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(releaseFolder), ImageType.ReleaseSecondary, SearchOption.TopDirectoryOnly);
|
||||
if(releaseImagesInFolder.Any())
|
||||
if (releaseImagesInFolder.Any())
|
||||
{
|
||||
result.Images = result.Images.Concat(releaseImagesInFolder.Select((x, i) => MakeFullsizeSecondaryImage(id, ImageType.ReleaseSecondary, i)));
|
||||
}
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Hashids.net" Version="1.2.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="2.2.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.4.0" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.13" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.15" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -278,7 +278,7 @@ namespace Roadie.Api.Services
|
|||
|
||||
protected Image MakeFullsizeSecondaryImage(Guid id, ImageType type, int imageId, string caption = null)
|
||||
{
|
||||
if(type == ImageType.ArtistSecondary)
|
||||
if (type == ImageType.ArtistSecondary)
|
||||
{
|
||||
return new Image($"{this.HttpContext.ImageBaseUrl }/artist-secondary/{id}/{imageId}", caption, $"{this.HttpContext.ImageBaseUrl }/artist-secondary/{id}/{ imageId }/{ this.Configuration.SmallImageSize.Width }/{ this.Configuration.SmallImageSize.Height }");
|
||||
}
|
||||
|
@ -305,6 +305,11 @@ namespace Roadie.Api.Services
|
|||
return "http://www.last.fm/music/" + this.HttpEncoder.UrlEncode($"{ artistName }/{ releaseTitle }");
|
||||
}
|
||||
|
||||
protected Image MakeNewImage(string type)
|
||||
{
|
||||
return new Image($"{this.HttpContext.ImageBaseUrl }/{type}.jpg", null, null);
|
||||
}
|
||||
|
||||
protected Image MakePlaylistThumbnailImage(Guid id)
|
||||
{
|
||||
return MakeThumbnailImage(id, "playlist");
|
||||
|
@ -424,7 +429,7 @@ namespace Roadie.Api.Services
|
|||
else
|
||||
{
|
||||
release.Rating = 0;
|
||||
}
|
||||
}
|
||||
release.LastUpdated = now;
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
await this.UpdateReleaseRank(release.Id);
|
||||
|
@ -444,7 +449,7 @@ namespace Roadie.Api.Services
|
|||
protected async Task<OperationResult<short>> SetTrackRating(Guid trackId, ApplicationUser user, short rating)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
|
||||
var track = this.DbContext.Tracks
|
||||
.Include(x => x.ReleaseMedia)
|
||||
.Include(x => x.ReleaseMedia.Release)
|
||||
|
@ -478,7 +483,8 @@ namespace Roadie.Api.Services
|
|||
if (ratings != null && ratings.Any())
|
||||
{
|
||||
track.Rating = (short)ratings.Average(x => (decimal)x);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
track.Rating = 0;
|
||||
}
|
||||
|
@ -490,7 +496,7 @@ namespace Roadie.Api.Services
|
|||
this.CacheManager.ClearRegion(track.CacheRegion);
|
||||
this.CacheManager.ClearRegion(track.ReleaseMedia.Release.CacheRegion);
|
||||
this.CacheManager.ClearRegion(track.ReleaseMedia.Release.Artist.CacheRegion);
|
||||
if(track.TrackArtist != null)
|
||||
if (track.TrackArtist != null)
|
||||
{
|
||||
this.CacheManager.ClearRegion(track.TrackArtist.CacheRegion);
|
||||
}
|
||||
|
@ -779,6 +785,78 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update Artist Rank
|
||||
/// Artist Rank is a sum of the artists release ranks + artist tracks rating + artist user rating
|
||||
/// </summary>
|
||||
protected async Task UpdateArtistRank(int artistId, bool updateReleaseRanks = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
var artist = this.DbContext.Artists.FirstOrDefault(x => x.Id == artistId);
|
||||
if (artist != null)
|
||||
{
|
||||
if (updateReleaseRanks)
|
||||
{
|
||||
var artistReleaseIds = this.DbContext.Releases.Where(x => x.ArtistId == artistId).Select(x => x.Id).ToArray();
|
||||
foreach (var artistReleaseId in artistReleaseIds)
|
||||
{
|
||||
await this.UpdateReleaseRank(artistReleaseId, false);
|
||||
}
|
||||
}
|
||||
|
||||
var artistTrackAverage = (from t in this.DbContext.Tracks
|
||||
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join ut in this.DbContext.UserTracks on t.Id equals ut.TrackId
|
||||
where t.ArtistId == artist.Id
|
||||
select ut.Rating).Select(x => (decimal?)x).Average();
|
||||
|
||||
var artistReleaseRatingRating = (from r in this.DbContext.Releases
|
||||
join ur in this.DbContext.UserReleases on r.Id equals ur.ReleaseId
|
||||
where r.ArtistId == artist.Id
|
||||
select ur.Rating).Select(x => (decimal?)x).Average();
|
||||
|
||||
var artistReleaseRankSum = (from r in this.DbContext.Releases
|
||||
where r.ArtistId == artist.Id
|
||||
select r.Rank).ToArray().Sum(x => x) ?? 0;
|
||||
|
||||
artist.Rank = SafeParser.ToNumber<decimal>(artistTrackAverage + artistReleaseRatingRating) + artistReleaseRankSum + artist.Rating;
|
||||
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
this.CacheManager.ClearRegion(artist.CacheRegion);
|
||||
this.Logger.LogInformation("UpdatedArtistRank For Artist `{0}`", artist);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex, "Error in UpdateArtistRank ArtistId [{0}], UpdateReleaseRanks [{1}]", artistId, updateReleaseRanks);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find all artists involved with release and update their rank
|
||||
/// </summary>
|
||||
protected async Task UpdateArtistsRankForRelease(data.Release release)
|
||||
{
|
||||
if (release != null)
|
||||
{
|
||||
var artistsForRelease = new List<int>
|
||||
{
|
||||
release.ArtistId
|
||||
};
|
||||
var trackArtistsForRelease = (from t in this.DbContext.Tracks
|
||||
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
where rm.ReleaseId == release.Id
|
||||
where t.ArtistId.HasValue
|
||||
select t.ArtistId.Value).ToArray();
|
||||
artistsForRelease.AddRange(trackArtistsForRelease);
|
||||
foreach (var artistId in artistsForRelease.Distinct())
|
||||
{
|
||||
await this.UpdateArtistRank(artistId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task UpdateLabelCounts(int labelId, DateTime now)
|
||||
{
|
||||
var label = this.DbContext.Labels.FirstOrDefault(x => x.Id == labelId);
|
||||
|
@ -826,10 +904,10 @@ namespace Roadie.Api.Services
|
|||
if (release != null)
|
||||
{
|
||||
release.PlayedCount = (from t in this.DbContext.Tracks
|
||||
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
where rm.ReleaseId == releaseId
|
||||
where t.PlayedCount.HasValue
|
||||
select t).Sum(x => x.PlayedCount);
|
||||
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
where rm.ReleaseId == releaseId
|
||||
where t.PlayedCount.HasValue
|
||||
select t).Sum(x => x.PlayedCount);
|
||||
release.Duration = (from t in this.DbContext.Tracks
|
||||
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
where rm.ReleaseId == releaseId
|
||||
|
@ -839,78 +917,6 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find all artists involved with release and update their rank
|
||||
/// </summary>
|
||||
protected async Task UpdateArtistsRankForRelease(data.Release release)
|
||||
{
|
||||
if(release != null)
|
||||
{
|
||||
var artistsForRelease = new List<int>
|
||||
{
|
||||
release.ArtistId
|
||||
};
|
||||
var trackArtistsForRelease = (from t in this.DbContext.Tracks
|
||||
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
where rm.ReleaseId == release.Id
|
||||
where t.ArtistId.HasValue
|
||||
select t.ArtistId.Value).ToArray();
|
||||
artistsForRelease.AddRange(trackArtistsForRelease);
|
||||
foreach(var artistId in artistsForRelease.Distinct())
|
||||
{
|
||||
await this.UpdateArtistRank(artistId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update Artist Rank
|
||||
/// Artist Rank is a sum of the artists release ranks + artist tracks rating + artist user rating
|
||||
/// </summary>
|
||||
protected async Task UpdateArtistRank(int artistId, bool updateReleaseRanks = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
var artist = this.DbContext.Artists.FirstOrDefault(x => x.Id == artistId);
|
||||
if (artist != null)
|
||||
{
|
||||
if (updateReleaseRanks)
|
||||
{
|
||||
var artistReleaseIds = this.DbContext.Releases.Where(x => x.ArtistId == artistId).Select(x => x.Id).ToArray();
|
||||
foreach (var artistReleaseId in artistReleaseIds)
|
||||
{
|
||||
await this.UpdateReleaseRank(artistReleaseId, false);
|
||||
}
|
||||
}
|
||||
|
||||
var artistTrackAverage = (from t in this.DbContext.Tracks
|
||||
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join ut in this.DbContext.UserTracks on t.Id equals ut.TrackId
|
||||
where t.ArtistId == artist.Id
|
||||
select ut.Rating).Select(x => (decimal?)x).Average();
|
||||
|
||||
var artistReleaseRatingRating = (from r in this.DbContext.Releases
|
||||
join ur in this.DbContext.UserReleases on r.Id equals ur.ReleaseId
|
||||
where r.ArtistId == artist.Id
|
||||
select ur.Rating).Select(x => (decimal?)x).Average();
|
||||
|
||||
var artistReleaseRankSum = (from r in this.DbContext.Releases
|
||||
where r.ArtistId == artist.Id
|
||||
select r.Rank).ToArray().Sum(x => x) ?? 0;
|
||||
|
||||
artist.Rank = SafeParser.ToNumber<decimal>(artistTrackAverage + artistReleaseRatingRating) + artistReleaseRankSum + artist.Rating;
|
||||
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
this.CacheManager.ClearRegion(artist.CacheRegion);
|
||||
this.Logger.LogInformation("UpdatedArtistRank For Artist `{0}`", artist);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex, "Error in UpdateArtistRank ArtistId [{0}], UpdateReleaseRanks [{1}]", artistId, updateReleaseRanks);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update Relase Rank
|
||||
/// Release Rank Calculation = Average of Track User Ratings + (User Rating of Release / Release Track Count) + Collection Rank Value
|
||||
|
@ -963,12 +969,6 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
}
|
||||
|
||||
protected Image MakeNewImage(string type)
|
||||
{
|
||||
return new Image($"{this.HttpContext.ImageBaseUrl }/{type}.jpg", null, null);
|
||||
}
|
||||
|
||||
|
||||
private Image MakeImage(Guid id, string type, int? width, int? height, string caption = null, bool includeCachebuster = false)
|
||||
{
|
||||
if (width.HasValue && height.HasValue && (width.Value != this.Configuration.ThumbnailImageSize.Width || height.Value != this.Configuration.ThumbnailImageSize.Height))
|
||||
|
|
|
@ -112,7 +112,6 @@ namespace Roadie.Api.Services
|
|||
result.LastScan = lastScan.CreatedDate;
|
||||
}
|
||||
sw.Stop();
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -964,7 +964,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
directory.id = subsonic.Request.ReleaseIdIdentifier + release.RoadieId.ToString();
|
||||
directory.name = release.Title;
|
||||
var releaseRating = user == null ? null : this.DbContext.UserReleases.FirstOrDefault(x =>x.UserId == user.Id && x.ReleaseId == release.Id);
|
||||
var releaseRating = user == null ? null : this.DbContext.UserReleases.FirstOrDefault(x => x.UserId == user.Id && x.ReleaseId == release.Id);
|
||||
directory.averageRating = release.Rating ?? 0;
|
||||
directory.parent = subsonic.Request.ArtistIdIdentifier + release.Artist.RoadieId.ToString();
|
||||
if (releaseRating?.IsFavorite ?? false)
|
||||
|
|
|
@ -28,8 +28,8 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public class TrackService : ServiceBase, ITrackService
|
||||
{
|
||||
private IBookmarkService BookmarkService { get; } = null;
|
||||
private IAdminService AdminService { get; }
|
||||
private IBookmarkService BookmarkService { get; } = null;
|
||||
|
||||
public TrackService(IRoadieSettings configuration,
|
||||
IHttpEncoder httpEncoder,
|
||||
|
@ -226,13 +226,13 @@ namespace Roadie.Api.Services
|
|||
if (!request.FilterRatedOnly && !request.FilterFavoriteOnly)
|
||||
{
|
||||
var sql = @"SELECT t.id
|
||||
FROM `track` t
|
||||
FROM `track` t
|
||||
JOIN `releasemedia` rm on (t.releaseMediaId = rm.id)
|
||||
WHERE t.Hash IS NOT NULL
|
||||
WHERE t.Hash IS NOT NULL
|
||||
AND t.id NOT IN (SELECT ut.trackId
|
||||
FROM `usertrack` ut
|
||||
WHERE ut.userId = {0}
|
||||
AND ut.isDisliked = 1)
|
||||
AND ut.isDisliked = 1)
|
||||
AND rm.releaseId in (select distinct r.id
|
||||
FROM `release` r
|
||||
WHERE r.id NOT IN (SELECT ur.releaseId
|
||||
|
@ -240,28 +240,28 @@ namespace Roadie.Api.Services
|
|||
WHERE ur.userId = {0}
|
||||
AND ur.isDisliked = 1)
|
||||
AND r.artistId IN (select DISTINCT a.id
|
||||
FROM `artist` a
|
||||
FROM `artist` a
|
||||
WHERE a.id NOT IN (select ua.artistId
|
||||
FROM `userartist` ua
|
||||
FROM `userartist` ua
|
||||
where ua.userId = {0}
|
||||
AND ua.isDisliked = 1)
|
||||
ORDER BY RAND())
|
||||
ORDER BY RAND())
|
||||
ORDER BY RAND()
|
||||
ORDER BY RAND()
|
||||
LIMIT {1}";
|
||||
randomTrackIds = this.DbContext.Tracks.FromSql(sql, userId, request.Limit).Select(x => x.Id).ToArray();
|
||||
}
|
||||
if (request.FilterRatedOnly && !request.FilterFavoriteOnly)
|
||||
{
|
||||
var sql = @"SELECT t.id
|
||||
FROM `track` t
|
||||
FROM `track` t
|
||||
JOIN `releasemedia` rm on (t.releaseMediaId = rm.id)
|
||||
WHERE t.Hash IS NOT NULL
|
||||
WHERE t.Hash IS NOT NULL
|
||||
AND t.rating > 0
|
||||
AND t.id NOT IN (SELECT ut.trackId
|
||||
FROM `usertrack` ut
|
||||
WHERE ut.userId = {0}
|
||||
AND ut.isDisliked = 1)
|
||||
AND ut.isDisliked = 1)
|
||||
AND rm.releaseId in (select distinct r.id
|
||||
FROM `release` r
|
||||
WHERE r.id NOT IN (SELECT ur.releaseId
|
||||
|
@ -269,14 +269,14 @@ namespace Roadie.Api.Services
|
|||
WHERE ur.userId = {0}
|
||||
AND ur.isDisliked = 1)
|
||||
AND r.artistId IN (select DISTINCT a.id
|
||||
FROM `artist` a
|
||||
FROM `artist` a
|
||||
WHERE a.id NOT IN (select ua.artistId
|
||||
FROM `userartist` ua
|
||||
FROM `userartist` ua
|
||||
where ua.userId = {0}
|
||||
AND ua.isDisliked = 1)
|
||||
ORDER BY RAND())
|
||||
ORDER BY RAND())
|
||||
ORDER BY RAND()
|
||||
ORDER BY RAND()
|
||||
LIMIT {1}";
|
||||
randomTrackIds = this.DbContext.Tracks.FromSql(sql, userId, request.LimitValue).Select(x => x.Id).ToArray();
|
||||
}
|
||||
|
@ -334,8 +334,8 @@ namespace Roadie.Api.Services
|
|||
where (releaseId == null || (releaseId != null && r.RoadieId == releaseId))
|
||||
where (filterToTrackIds == null || filterToTrackIds.Contains(t.RoadieId))
|
||||
where (request.FilterMinimumRating == null || t.Rating >= request.FilterMinimumRating.Value)
|
||||
where (request.FilterValue == "" || (t.Title.Contains(request.FilterValue) ||
|
||||
t.AlternateNames.Contains(request.FilterValue) ||
|
||||
where (request.FilterValue == "" || (t.Title.Contains(request.FilterValue) ||
|
||||
t.AlternateNames.Contains(request.FilterValue) ||
|
||||
t.AlternateNames.Contains(normalizedFilterValue)) ||
|
||||
t.PartTitles.Contains(request.FilterValue))
|
||||
where (!isEqualFilter || (t.Title.Equals(request.FilterValue) ||
|
||||
|
@ -486,14 +486,14 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
sortBy = string.IsNullOrEmpty(request.Sort) ? request.OrderValue(new Dictionary<string, string> { { "Release.Release.Text", "ASC" }, { "MediaNumber", "ASC" }, { "TrackNumber", "ASC" } }) : request.OrderValue(null);
|
||||
}
|
||||
if(doRandomize ?? false)
|
||||
if (doRandomize ?? false)
|
||||
{
|
||||
rows = result.OrderBy(x => x.RandomSortId).Take(request.LimitValue).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
|
||||
}
|
||||
}
|
||||
if (rows.Any() && roadieUser != null)
|
||||
{
|
||||
var rowIds = rows.Select(x => x.DatabaseId).ToArray();
|
||||
|
@ -599,6 +599,140 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fast as possible check if exists and return minimum information on Track
|
||||
/// </summary>
|
||||
public OperationResult<Track> StreamCheckAndInfo(User roadieUser, Guid id)
|
||||
{
|
||||
var track = this.DbContext.Tracks.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (track == null)
|
||||
{
|
||||
return new OperationResult<Track>(true, string.Format("Track Not Found [{0}]", id));
|
||||
}
|
||||
return new OperationResult<Track>()
|
||||
{
|
||||
Data = track.Adapt<Track>(),
|
||||
IsSuccess = true
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<TrackStreamInfo>> TrackStreamInfo(Guid trackId, long beginBytes, long endBytes, User roadieUser)
|
||||
{
|
||||
var track = this.DbContext.Tracks.FirstOrDefault(x => x.RoadieId == trackId);
|
||||
if (track == null)
|
||||
{
|
||||
// Not Found try recanning release
|
||||
var release = (from r in this.DbContext.Releases
|
||||
join rm in this.DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
||||
where rm.Id == track.ReleaseMediaId
|
||||
select r).FirstOrDefault();
|
||||
if (!release.IsLocked ?? false)
|
||||
{
|
||||
await this.AdminService.ScanRelease(new Library.Identity.ApplicationUser
|
||||
{
|
||||
Id = roadieUser.Id.Value
|
||||
}, release.RoadieId, false, true);
|
||||
}
|
||||
track = this.DbContext.Tracks.FirstOrDefault(x => x.RoadieId == trackId);
|
||||
if (track == null)
|
||||
{
|
||||
return new OperationResult<TrackStreamInfo>($"TrackStreamInfo: Unable To Find Track [{ trackId }]");
|
||||
}
|
||||
}
|
||||
if (!track.IsValid)
|
||||
{
|
||||
return new OperationResult<TrackStreamInfo>($"TrackStreamInfo: Invalid Track. Track Id [{trackId}], FilePath [{track.FilePath}], Filename [{track.FileName}]");
|
||||
}
|
||||
string trackPath = null;
|
||||
try
|
||||
{
|
||||
trackPath = track.PathToTrack(this.Configuration, this.Configuration.LibraryFolder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperationResult<TrackStreamInfo>(ex);
|
||||
}
|
||||
var trackFileInfo = new FileInfo(trackPath);
|
||||
if (!trackFileInfo.Exists)
|
||||
{
|
||||
// Not Found try recanning release
|
||||
var release = (from r in this.DbContext.Releases
|
||||
join rm in this.DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
||||
where rm.Id == track.ReleaseMediaId
|
||||
select r).FirstOrDefault();
|
||||
if (!release.IsLocked ?? false)
|
||||
{
|
||||
await this.AdminService.ScanRelease(new Library.Identity.ApplicationUser
|
||||
{
|
||||
Id = roadieUser.Id.Value
|
||||
}, release.RoadieId, false, true);
|
||||
}
|
||||
track = this.DbContext.Tracks.FirstOrDefault(x => x.RoadieId == trackId);
|
||||
if (track == null)
|
||||
{
|
||||
return new OperationResult<TrackStreamInfo>($"TrackStreamInfo: Unable To Find Track [{ trackId }]");
|
||||
}
|
||||
try
|
||||
{
|
||||
trackPath = track.PathToTrack(this.Configuration, this.Configuration.LibraryFolder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperationResult<TrackStreamInfo>(ex);
|
||||
}
|
||||
if (!trackFileInfo.Exists)
|
||||
{
|
||||
track.UpdateTrackMissingFile();
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
return new OperationResult<TrackStreamInfo>($"TrackStreamInfo: TrackId [{trackId}] Unable to Find Track [{trackFileInfo.FullName}]");
|
||||
}
|
||||
}
|
||||
var contentDurationTimeSpan = TimeSpan.FromMilliseconds((double)(track.Duration ?? 0));
|
||||
var info = new TrackStreamInfo
|
||||
{
|
||||
FileName = this.HttpEncoder.UrlEncode(track.FileName).ToContentDispositionFriendly(),
|
||||
ContentDisposition = $"attachment; filename=\"{ this.HttpEncoder.UrlEncode(track.FileName).ToContentDispositionFriendly() }\"",
|
||||
ContentDuration = contentDurationTimeSpan.TotalSeconds.ToString(),
|
||||
};
|
||||
var cacheTimeout = 86400; // 24 hours
|
||||
var contentLength = (endBytes - beginBytes) + 1;
|
||||
info.Track = new DataToken
|
||||
{
|
||||
Text = track.Title,
|
||||
Value = track.RoadieId.ToString()
|
||||
};
|
||||
info.BeginBytes = beginBytes;
|
||||
info.EndBytes = endBytes;
|
||||
info.ContentRange = $"bytes {beginBytes}-{endBytes}/{contentLength}";
|
||||
info.ContentLength = contentLength.ToString();
|
||||
info.IsFullRequest = beginBytes == 0 && endBytes == (trackFileInfo.Length - 1);
|
||||
info.IsEndRangeRequest = beginBytes > 0 && endBytes != (trackFileInfo.Length - 1);
|
||||
info.LastModified = (track.LastUpdated ?? track.CreatedDate).ToString("R");
|
||||
info.Etag = track.Etag;
|
||||
info.CacheControl = $"public, max-age={ cacheTimeout.ToString() } ";
|
||||
info.Expires = DateTime.UtcNow.AddMinutes(cacheTimeout).ToString("R");
|
||||
int bytesToRead = (int)(endBytes - beginBytes) + 1;
|
||||
byte[] trackBytes = new byte[bytesToRead];
|
||||
using (var fs = trackFileInfo.OpenRead())
|
||||
{
|
||||
try
|
||||
{
|
||||
fs.Seek(beginBytes, SeekOrigin.Begin);
|
||||
var r = fs.Read(trackBytes, 0, bytesToRead);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperationResult<TrackStreamInfo>(ex);
|
||||
}
|
||||
}
|
||||
info.Bytes = trackBytes;
|
||||
return new OperationResult<TrackStreamInfo>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = info
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdateTrack(User user, Track model)
|
||||
{
|
||||
var didChangeTrack = false;
|
||||
|
@ -682,141 +816,6 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Fast as possible check if exists and return minimum information on Track
|
||||
/// </summary>
|
||||
public OperationResult<Track> StreamCheckAndInfo(User roadieUser, Guid id)
|
||||
{
|
||||
var track = this.DbContext.Tracks.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (track == null)
|
||||
{
|
||||
return new OperationResult<Track>(true, string.Format("Track Not Found [{0}]", id));
|
||||
}
|
||||
return new OperationResult<Track>()
|
||||
{
|
||||
Data = track.Adapt<Track>(),
|
||||
IsSuccess = true
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<TrackStreamInfo>> TrackStreamInfo(Guid trackId, long beginBytes, long endBytes, User roadieUser)
|
||||
{
|
||||
var track = this.DbContext.Tracks.FirstOrDefault(x => x.RoadieId == trackId);
|
||||
if (track == null)
|
||||
{
|
||||
// Not Found try recanning release
|
||||
var release = (from r in this.DbContext.Releases
|
||||
join rm in this.DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
||||
where rm.Id == track.ReleaseMediaId
|
||||
select r).FirstOrDefault();
|
||||
if (!release.IsLocked ?? false)
|
||||
{
|
||||
await this.AdminService.ScanRelease(new Library.Identity.ApplicationUser
|
||||
{
|
||||
Id = roadieUser.Id.Value
|
||||
}, release.RoadieId, false, true);
|
||||
}
|
||||
track = this.DbContext.Tracks.FirstOrDefault(x => x.RoadieId == trackId);
|
||||
if(track == null)
|
||||
{
|
||||
return new OperationResult<TrackStreamInfo>($"TrackStreamInfo: Unable To Find Track [{ trackId }]");
|
||||
}
|
||||
}
|
||||
if (!track.IsValid)
|
||||
{
|
||||
return new OperationResult<TrackStreamInfo>($"TrackStreamInfo: Invalid Track. Track Id [{trackId}], FilePath [{track.FilePath}], Filename [{track.FileName}]");
|
||||
}
|
||||
string trackPath = null;
|
||||
try
|
||||
{
|
||||
trackPath = track.PathToTrack(this.Configuration, this.Configuration.LibraryFolder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperationResult<TrackStreamInfo>(ex);
|
||||
}
|
||||
var trackFileInfo = new FileInfo(trackPath);
|
||||
if (!trackFileInfo.Exists)
|
||||
{
|
||||
// Not Found try recanning release
|
||||
var release = (from r in this.DbContext.Releases
|
||||
join rm in this.DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
||||
where rm.Id == track.ReleaseMediaId
|
||||
select r).FirstOrDefault();
|
||||
if (!release.IsLocked ?? false)
|
||||
{
|
||||
await this.AdminService.ScanRelease(new Library.Identity.ApplicationUser
|
||||
{
|
||||
Id = roadieUser.Id.Value
|
||||
}, release.RoadieId, false, true);
|
||||
}
|
||||
track = this.DbContext.Tracks.FirstOrDefault(x => x.RoadieId == trackId);
|
||||
if (track == null)
|
||||
{
|
||||
return new OperationResult<TrackStreamInfo>($"TrackStreamInfo: Unable To Find Track [{ trackId }]");
|
||||
}
|
||||
try
|
||||
{
|
||||
trackPath = track.PathToTrack(this.Configuration, this.Configuration.LibraryFolder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperationResult<TrackStreamInfo>(ex);
|
||||
}
|
||||
if (!trackFileInfo.Exists)
|
||||
{
|
||||
track.UpdateTrackMissingFile();
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
return new OperationResult<TrackStreamInfo>($"TrackStreamInfo: TrackId [{trackId}] Unable to Find Track [{trackFileInfo.FullName}]");
|
||||
}
|
||||
}
|
||||
var contentDurationTimeSpan = TimeSpan.FromMilliseconds((double)(track.Duration ?? 0));
|
||||
var info = new TrackStreamInfo
|
||||
{
|
||||
FileName = this.HttpEncoder.UrlEncode(track.FileName).ToContentDispositionFriendly(),
|
||||
ContentDisposition = $"attachment; filename=\"{ this.HttpEncoder.UrlEncode(track.FileName).ToContentDispositionFriendly() }\"",
|
||||
ContentDuration = contentDurationTimeSpan.TotalSeconds.ToString(),
|
||||
};
|
||||
var cacheTimeout = 86400; // 24 hours
|
||||
var contentLength = (endBytes - beginBytes) + 1;
|
||||
info.Track = new DataToken
|
||||
{
|
||||
Text = track.Title,
|
||||
Value = track.RoadieId.ToString()
|
||||
};
|
||||
info.BeginBytes = beginBytes;
|
||||
info.EndBytes = endBytes;
|
||||
info.ContentRange = $"bytes {beginBytes}-{endBytes}/{contentLength}";
|
||||
info.ContentLength = contentLength.ToString();
|
||||
info.IsFullRequest = beginBytes == 0 && endBytes == (trackFileInfo.Length - 1);
|
||||
info.IsEndRangeRequest = beginBytes > 0 && endBytes != (trackFileInfo.Length - 1);
|
||||
info.LastModified = (track.LastUpdated ?? track.CreatedDate).ToString("R");
|
||||
info.Etag = track.Etag;
|
||||
info.CacheControl = $"public, max-age={ cacheTimeout.ToString() } ";
|
||||
info.Expires = DateTime.UtcNow.AddMinutes(cacheTimeout).ToString("R");
|
||||
int bytesToRead = (int)(endBytes - beginBytes) + 1;
|
||||
byte[] trackBytes = new byte[bytesToRead];
|
||||
using (var fs = trackFileInfo.OpenRead())
|
||||
{
|
||||
try
|
||||
{
|
||||
fs.Seek(beginBytes, SeekOrigin.Begin);
|
||||
var r = fs.Read(trackBytes, 0, bytesToRead);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperationResult<TrackStreamInfo>(ex);
|
||||
}
|
||||
}
|
||||
info.Bytes = trackBytes;
|
||||
return new OperationResult<TrackStreamInfo>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = info
|
||||
};
|
||||
}
|
||||
|
||||
private Task<OperationResult<Track>> TrackByIdAction(Guid id, IEnumerable<string> includes)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
|
|
@ -365,7 +365,7 @@ namespace Roadie.Api.Services
|
|||
public async Task<OperationResult<short>> SetTrackRating(Guid trackId, User roadieUser, short rating)
|
||||
{
|
||||
var timings = new Dictionary<string, long>();
|
||||
var sw = Stopwatch.StartNew();
|
||||
var sw = Stopwatch.StartNew();
|
||||
var user = this.GetUser(roadieUser.UserId);
|
||||
sw.Stop();
|
||||
timings.Add("GetUser", sw.ElapsedMilliseconds);
|
||||
|
|
|
@ -24,18 +24,13 @@ namespace Roadie.Api.Controllers
|
|||
[AllowAnonymous]
|
||||
public class AccountController : ControllerBase
|
||||
{
|
||||
private string _baseUrl = null;
|
||||
|
||||
private readonly IConfiguration Configuration;
|
||||
private readonly ILogger<AccountController> Logger;
|
||||
private readonly SignInManager<ApplicationUser> SignInManager;
|
||||
private readonly ITokenService TokenService;
|
||||
private readonly UserManager<ApplicationUser> UserManager;
|
||||
private string _baseUrl = null;
|
||||
private IAdminService AdminService { get; }
|
||||
private ICacheManager CacheManager { get; }
|
||||
private IEmailSender EmailSender { get; }
|
||||
private IHttpContext RoadieHttpContext { get; }
|
||||
private IRoadieSettings RoadieSettings { get; }
|
||||
|
||||
private string BaseUrl
|
||||
{
|
||||
|
@ -59,6 +54,11 @@ namespace Roadie.Api.Controllers
|
|||
}
|
||||
}
|
||||
|
||||
private ICacheManager CacheManager { get; }
|
||||
private IEmailSender EmailSender { get; }
|
||||
private IHttpContext RoadieHttpContext { get; }
|
||||
private IRoadieSettings RoadieSettings { get; }
|
||||
|
||||
public AccountController(
|
||||
IAdminService adminService,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
|
@ -277,7 +277,7 @@ namespace Roadie.Api.Controllers
|
|||
public async Task<IActionResult> SendPasswordResetEmail(string username, string callbackUrl)
|
||||
{
|
||||
var user = await UserManager.FindByNameAsync(username);
|
||||
if(user == null)
|
||||
if (user == null)
|
||||
{
|
||||
this.Logger.LogError($"Unable to find user by username [{ username }]");
|
||||
return StatusCode(500);
|
||||
|
|
|
@ -35,12 +35,11 @@ namespace Roadie.Api.Controllers
|
|||
return Ok();
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("scan/inbound")]
|
||||
[HttpPost("delete/artist/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanInbound()
|
||||
public async Task<IActionResult> DeleteArtist(Guid id)
|
||||
{
|
||||
var result = await this.AdminService.ScanInboundFolder(await this.UserManager.GetUserAsync(User));
|
||||
var result = await this.AdminService.DeleteArtist(await this.UserManager.GetUserAsync(User), id);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
|
@ -48,11 +47,11 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("scan/library")]
|
||||
[HttpPost("delete/artist/releases/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanLibrary()
|
||||
public async Task<IActionResult> DeleteArtistReleases(Guid id)
|
||||
{
|
||||
var result = await this.AdminService.ScanLibraryFolder(await this.UserManager.GetUserAsync(User));
|
||||
var result = await this.AdminService.DeleteArtistReleases(await this.UserManager.GetUserAsync(User), id);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
|
@ -60,11 +59,11 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("scan/artist/{id}")]
|
||||
[HttpPost("delete/artistsecondaryimage/{id}/{index}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanArtist(Guid id)
|
||||
public async Task<IActionResult> DeleteArtistSecondaryImage(Guid id, int index)
|
||||
{
|
||||
var result = await this.AdminService.ScanArtist(await this.UserManager.GetUserAsync(User), id);
|
||||
var result = await this.AdminService.DeleteArtistSecondaryImage(await this.UserManager.GetUserAsync(User), id, index);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
|
@ -72,55 +71,6 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("scan/release/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanRelease(Guid id)
|
||||
{
|
||||
var result = await this.AdminService.ScanRelease(await this.UserManager.GetUserAsync(User), id);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("scan/collection/rescanall")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanAllCollections()
|
||||
{
|
||||
var result = await this.AdminService.ScanAllCollections(await this.UserManager.GetUserAsync(User));
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("scan/collection/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanCollection(Guid id)
|
||||
{
|
||||
var result = await this.AdminService.ScanCollection(await this.UserManager.GetUserAsync(User), id);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("missingcollectionreleases")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> MissingCollectionReleases()
|
||||
{
|
||||
var result = await this.AdminService.MissingCollectionReleases(await this.UserManager.GetUserAsync(User));
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("delete/release/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteRelease(Guid id, bool? doDeleteFiles)
|
||||
|
@ -145,11 +95,11 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("delete/artist/{id}")]
|
||||
[HttpPost("delete/user/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteArtist(Guid id)
|
||||
public async Task<IActionResult> DeleteUser(Guid id)
|
||||
{
|
||||
var result = await this.AdminService.DeleteArtist(await this.UserManager.GetUserAsync(User), id);
|
||||
var result = await this.AdminService.DeleteUser(await this.UserManager.GetUserAsync(User), id);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
|
@ -157,11 +107,11 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("delete/artistsecondaryimage/{id}/{index}")]
|
||||
[HttpPost("missingcollectionreleases")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteArtistSecondaryImage(Guid id, int index)
|
||||
public async Task<IActionResult> MissingCollectionReleases()
|
||||
{
|
||||
var result = await this.AdminService.DeleteArtistSecondaryImage(await this.UserManager.GetUserAsync(User), id, index);
|
||||
var result = await this.AdminService.MissingCollectionReleases(await this.UserManager.GetUserAsync(User));
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
|
@ -169,12 +119,71 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("delete/artist/releases/{id}")]
|
||||
[HttpPost("scan/collection/rescanall")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteArtistReleases(Guid id)
|
||||
public async Task<IActionResult> ScanAllCollections()
|
||||
{
|
||||
var result = await this.AdminService.DeleteArtistReleases(await this.UserManager.GetUserAsync(User), id);
|
||||
var result = await this.AdminService.ScanAllCollections(await this.UserManager.GetUserAsync(User));
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("scan/artist/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanArtist(Guid id)
|
||||
{
|
||||
var result = await this.AdminService.ScanArtist(await this.UserManager.GetUserAsync(User), id);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("scan/collection/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanCollection(Guid id)
|
||||
{
|
||||
var result = await this.AdminService.ScanCollection(await this.UserManager.GetUserAsync(User), id);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("scan/inbound")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanInbound()
|
||||
{
|
||||
var result = await this.AdminService.ScanInboundFolder(await this.UserManager.GetUserAsync(User));
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("scan/library")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanLibrary()
|
||||
{
|
||||
var result = await this.AdminService.ScanLibraryFolder(await this.UserManager.GetUserAsync(User));
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("scan/release/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanRelease(Guid id)
|
||||
{
|
||||
var result = await this.AdminService.ScanRelease(await this.UserManager.GetUserAsync(User), id);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
|
|
|
@ -98,7 +98,6 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("setImageByUrl/{id}/{imageUrl}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
|
@ -117,24 +116,6 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("uploadImage/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
|
||||
{
|
||||
var result = await this.ArtistService.UploadArtistImage(await this.CurrentUserModel(), id, file);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("edit")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
|
@ -157,6 +138,22 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("uploadImage/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
|
||||
{
|
||||
var result = await this.ArtistService.UploadArtistImage(await this.CurrentUserModel(), id, file);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,23 +29,6 @@ namespace Roadie.Api.Controllers
|
|||
this.CollectionService = collectionService;
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Get(Guid id, string inc = null)
|
||||
{
|
||||
var result = await this.CollectionService.ById(await this.CurrentUserModel(), id, (inc ?? models.Collections.Collection.DefaultIncludes).ToLower().Split(","));
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("add")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
|
@ -59,28 +42,6 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("edit")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> Update(models.Collections.Collection collection)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
var result = await this.CollectionService.UpdateCollection(await this.CurrentUserModel(), collection);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("delete/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
|
@ -95,6 +56,22 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Get(Guid id, string inc = null)
|
||||
{
|
||||
var result = await this.CollectionService.ById(await this.CurrentUserModel(), id, (inc ?? models.Collections.Collection.DefaultIncludes).ToLower().Split(","));
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(200)]
|
||||
|
@ -120,5 +97,27 @@ namespace Roadie.Api.Controllers
|
|||
}
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
[HttpPost("edit")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> Update(models.Collections.Collection collection)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
var result = await this.CollectionService.UpdateCollection(await this.CurrentUserModel(), collection);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,9 +25,9 @@ namespace Roadie.Api.Controllers
|
|||
public const string ControllerCacheRegionUrn = "urn:controller_cache";
|
||||
|
||||
private models.User _currentUser = null;
|
||||
protected ILogger Logger { get; set; }
|
||||
protected ICacheManager CacheManager { get; }
|
||||
protected IConfiguration Configuration { get; }
|
||||
protected ILogger Logger { get; set; }
|
||||
protected IRoadieSettings RoadieSettings { get; }
|
||||
protected UserManager<ApplicationUser> UserManager { get; }
|
||||
|
||||
|
@ -50,28 +50,16 @@ namespace Roadie.Api.Controllers
|
|||
this._currentUser = await this.CacheManager.GetAsync($"urn:controller_user:{ this.User.Identity.Name }", async () =>
|
||||
{
|
||||
return this.UserModelForUser(await this.UserManager.GetUserAsync(User));
|
||||
}, ControllerCacheRegionUrn);
|
||||
}, ControllerCacheRegionUrn);
|
||||
}
|
||||
}
|
||||
if(this._currentUser == null)
|
||||
if (this._currentUser == null)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Access Denied");
|
||||
}
|
||||
return this._currentUser;
|
||||
}
|
||||
|
||||
protected models.User UserModelForUser(ApplicationUser user)
|
||||
{
|
||||
if(user == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var result = user.Adapt<models.User>();
|
||||
result.IsAdmin = User.IsInRole("Admin");
|
||||
result.IsEditor = User.IsInRole("Editor") || result.IsAdmin;
|
||||
return result;
|
||||
}
|
||||
|
||||
protected async Task<IActionResult> StreamTrack(Guid id, ITrackService trackService, IPlayActivityService playActivityService, models.User currentUser = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
@ -81,7 +69,7 @@ namespace Roadie.Api.Controllers
|
|||
tsw.Restart();
|
||||
var user = currentUser ?? await this.CurrentUserModel();
|
||||
var track = trackService.StreamCheckAndInfo(user, id);
|
||||
if (track == null || ( track?.IsNotFoundResult ?? false))
|
||||
if (track == null || (track?.IsNotFoundResult ?? false))
|
||||
{
|
||||
if (track?.Errors != null && (track?.Errors.Any() ?? false))
|
||||
{
|
||||
|
@ -140,8 +128,18 @@ namespace Roadie.Api.Controllers
|
|||
sw.Stop();
|
||||
this.Logger.LogInformation($"StreamTrack ElapsedTime [{ sw.ElapsedMilliseconds }], Timings [{ JsonConvert.SerializeObject(timings) }] PlayActivity `{ playListUser?.Data.ToString() }`, StreamInfo `{ info?.Data.ToString() }`");
|
||||
return new EmptyResult();
|
||||
|
||||
}
|
||||
|
||||
protected models.User UserModelForUser(ApplicationUser user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var result = user.Adapt<models.User>();
|
||||
result.IsAdmin = User.IsInRole("Admin");
|
||||
result.IsEditor = User.IsInRole("Editor") || result.IsAdmin;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -75,7 +75,6 @@ namespace Roadie.Api.Controllers
|
|||
entityTag: result.ETag);
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("collection/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
|
@ -219,6 +218,56 @@ namespace Roadie.Api.Controllers
|
|||
entityTag: result.ETag);
|
||||
}
|
||||
|
||||
[HttpPost("search/artist/{query}/{resultsCount:int?}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> SearchForArtistImage(string query, int? resultsCount)
|
||||
{
|
||||
var result = await this.ImageService.Search(query, resultsCount ?? 10);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("search/label/{query}/{resultsCount:int?}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> SearchForLabelImage(string query, int? resultsCount)
|
||||
{
|
||||
var result = await this.ImageService.Search(query, resultsCount ?? 10);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("search/release/{query}/{resultsCount:int?}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> SearchForReleaseCover(string query, int? resultsCount)
|
||||
{
|
||||
var result = await this.ImageService.Search(query, resultsCount ?? 10);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("track/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
|
||||
[ProducesResponseType(200)]
|
||||
|
@ -264,57 +313,5 @@ namespace Roadie.Api.Controllers
|
|||
lastModified: result.LastModified,
|
||||
entityTag: result.ETag);
|
||||
}
|
||||
|
||||
[HttpPost("search/release/{query}/{resultsCount:int?}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> SearchForReleaseCover(string query, int? resultsCount)
|
||||
{
|
||||
var result = await this.ImageService.Search(query, resultsCount ?? 10);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("search/artist/{query}/{resultsCount:int?}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> SearchForArtistImage(string query, int? resultsCount)
|
||||
{
|
||||
var result = await this.ImageService.Search(query, resultsCount ?? 10);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("search/label/{query}/{resultsCount:int?}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> SearchForLabelImage(string query, int? resultsCount)
|
||||
{
|
||||
var result = await this.ImageService.Search(query, resultsCount ?? 10);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -74,24 +74,6 @@ namespace Roadie.Api.Controllers
|
|||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
[HttpPost("uploadImage/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
|
||||
{
|
||||
var result = await this.LabelService.UploadLabelImage(await this.CurrentUserModel(), id, file);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("setImageByUrl/{id}/{imageUrl}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
|
@ -131,5 +113,23 @@ namespace Roadie.Api.Controllers
|
|||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("uploadImage/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
|
||||
{
|
||||
var result = await this.LabelService.UploadLabelImage(await this.CurrentUserModel(), id, file);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,11 +3,9 @@ using Microsoft.AspNetCore.Identity;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Roadie.Api.Services;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
|
|
@ -8,7 +8,6 @@ using Roadie.Library.Caching;
|
|||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -73,11 +72,11 @@ namespace Roadie.Api.Controllers
|
|||
public async Task<IActionResult> StreamTrack(int userId, string trackPlayToken, Guid id)
|
||||
{
|
||||
var user = this.UserManager.Users.FirstOrDefault(x => x.Id == userId);
|
||||
if(user == null)
|
||||
if (user == null)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.Unauthorized);
|
||||
}
|
||||
if(!ServiceBase.ConfirmTrackPlayToken(user, id, trackPlayToken))
|
||||
if (!ServiceBase.ConfirmTrackPlayToken(user, id, trackPlayToken))
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.Unauthorized);
|
||||
}
|
||||
|
|
|
@ -6,11 +6,9 @@ using Microsoft.Extensions.Logging;
|
|||
using Roadie.Api.Services;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Playlists;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using models = Roadie.Library.Models;
|
||||
|
@ -32,36 +30,6 @@ namespace Roadie.Api.Controllers
|
|||
this.PlaylistService = playlistService;
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Get(Guid id, string inc = null)
|
||||
{
|
||||
var result = await this.PlaylistService.ById(await this.CurrentUserModel(), id, (inc ?? models.Playlists.Playlist.DefaultIncludes).ToLower().Split(","));
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> List([FromQuery]PagedRequest request, string inc)
|
||||
{
|
||||
var result = await this.PlaylistService.List(roadieUser: await this.CurrentUserModel(),
|
||||
request: request);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("add")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
|
@ -85,7 +53,7 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
return NotFound();
|
||||
}
|
||||
if(result != null && result.IsAccessDeniedResult)
|
||||
if (result != null && result.IsAccessDeniedResult)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.Forbidden);
|
||||
}
|
||||
|
@ -96,6 +64,36 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Get(Guid id, string inc = null)
|
||||
{
|
||||
var result = await this.PlaylistService.ById(await this.CurrentUserModel(), id, (inc ?? models.Playlists.Playlist.DefaultIncludes).ToLower().Split(","));
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> List([FromQuery]PagedRequest request, string inc)
|
||||
{
|
||||
var result = await this.PlaylistService.List(roadieUser: await this.CurrentUserModel(),
|
||||
request: request);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("edit")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
|
@ -133,8 +131,5 @@ namespace Roadie.Api.Controllers
|
|||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -4,14 +4,11 @@ using Microsoft.AspNetCore.Identity;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Roadie.Api.Services;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Data;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
@ -51,6 +48,33 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> List([FromQuery]PagedRequest request, string inc, bool? doRandomize = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await this.ReleaseService.List(user: await this.CurrentUserModel(),
|
||||
request: request,
|
||||
doRandomize: doRandomize ?? false,
|
||||
includes: (inc ?? models.Releases.Release.DefaultListIncludes).ToLower().Split(","));
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.Unauthorized);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
}
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
[HttpPost("mergeReleases/{releaseToMergeId}/{releaseToMergeIntoId}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
|
@ -69,17 +93,13 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("edit")]
|
||||
[HttpPost("setImageByUrl/{id}/{imageUrl}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[Authorize(Policy="Editor")]
|
||||
public async Task<IActionResult> Update(models.Releases.Release release)
|
||||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> SetReleaseImageByUrl(Guid id, string imageUrl)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
var result = await this.ReleaseService.UpdateRelease(await this.CurrentUserModel(), release);
|
||||
var result = await this.ReleaseService.SetReleaseImageByUrl(await this.CurrentUserModel(), id, HttpUtility.UrlDecode(imageUrl));
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -91,40 +111,17 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> List([FromQuery]PagedRequest request, string inc, bool? doRandomize = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await this.ReleaseService.List(user: await this.CurrentUserModel(),
|
||||
request: request,
|
||||
doRandomize: doRandomize ?? false,
|
||||
includes: (inc ?? models.Releases.Release.DefaultListIncludes).ToLower().Split(","));
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
catch(UnauthorizedAccessException)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.Unauthorized);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
}
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
[HttpPost("setImageByUrl/{id}/{imageUrl}")]
|
||||
[HttpPost("edit")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> SetReleaseImageByUrl(Guid id, string imageUrl)
|
||||
public async Task<IActionResult> Update(models.Releases.Release release)
|
||||
{
|
||||
var result = await this.ReleaseService.SetReleaseImageByUrl(await this.CurrentUserModel(), id, HttpUtility.UrlDecode(imageUrl));
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
var result = await this.ReleaseService.UpdateRelease(await this.CurrentUserModel(), release);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
|
|
|
@ -27,14 +27,6 @@ namespace Roadie.Api.Controllers
|
|||
this.StatisticsService = statisticsService;
|
||||
}
|
||||
|
||||
[HttpGet("ping")]
|
||||
[ProducesResponseType(200)]
|
||||
[AllowAnonymous]
|
||||
public IActionResult Ping()
|
||||
{
|
||||
return Ok("pong");
|
||||
}
|
||||
|
||||
[HttpGet("info")]
|
||||
[ProducesResponseType(200)]
|
||||
[AllowAnonymous]
|
||||
|
@ -62,6 +54,14 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(await this.StatisticsService.LibraryStatistics());
|
||||
}
|
||||
|
||||
[HttpGet("ping")]
|
||||
[ProducesResponseType(200)]
|
||||
[AllowAnonymous]
|
||||
public IActionResult Ping()
|
||||
{
|
||||
return Ok("pong");
|
||||
}
|
||||
|
||||
[HttpGet("releasesByDate")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ReleasesByDate()
|
||||
|
|
|
@ -43,6 +43,20 @@ namespace Roadie.Api.Controllers
|
|||
this.PlayActivityService = playActivityService;
|
||||
}
|
||||
|
||||
[HttpGet("addChatMessage.view")]
|
||||
[HttpPost("addChatMessage.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> AddChatMessage(SubsonicRequest request)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.AddChatMessage(request, this.SubsonicUser);
|
||||
return this.BuildResponse(request, result);
|
||||
}
|
||||
|
||||
[HttpGet("createBookmark.view")]
|
||||
[HttpPost("createBookmark.view")]
|
||||
[ProducesResponseType(200)]
|
||||
|
@ -276,6 +290,20 @@ namespace Roadie.Api.Controllers
|
|||
return this.BuildResponse(request, result, "bookmarks");
|
||||
}
|
||||
|
||||
[HttpGet("getChatMessages.view")]
|
||||
[HttpPost("getChatMessages.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> GetChatMessages(SubsonicRequest request, long? since)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.GetChatMessages(request, this.SubsonicUser, since);
|
||||
return this.BuildResponse(request, result, "chatMessages");
|
||||
}
|
||||
|
||||
[HttpGet("getCoverArt.view")]
|
||||
[HttpPost("getCoverArt.view")]
|
||||
[ProducesResponseType(200)]
|
||||
|
@ -404,20 +432,6 @@ namespace Roadie.Api.Controllers
|
|||
return this.BuildResponse(request, result, "playlists");
|
||||
}
|
||||
|
||||
[HttpGet("savePlayQueue.view")]
|
||||
[HttpPost("savePlayQueue.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> SavePlayQueue(SubsonicRequest request, string username, string current, long? position)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.SavePlayQueue(request, this.SubsonicUser, current, position);
|
||||
return this.BuildResponse(request, result);
|
||||
}
|
||||
|
||||
[HttpGet("getPlayQueue.view")]
|
||||
[HttpPost("getPlayQueue.view")]
|
||||
[ProducesResponseType(200)]
|
||||
|
@ -562,34 +576,6 @@ namespace Roadie.Api.Controllers
|
|||
return this.BuildResponse(request, result, "topSongs");
|
||||
}
|
||||
|
||||
[HttpGet("getChatMessages.view")]
|
||||
[HttpPost("getChatMessages.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> GetChatMessages(SubsonicRequest request, long? since)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.GetChatMessages(request, this.SubsonicUser, since);
|
||||
return this.BuildResponse(request, result, "chatMessages");
|
||||
}
|
||||
|
||||
[HttpGet("addChatMessage.view")]
|
||||
[HttpPost("addChatMessage.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> AddChatMessage(SubsonicRequest request)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.AddChatMessage(request, this.SubsonicUser);
|
||||
return this.BuildResponse(request, result);
|
||||
}
|
||||
|
||||
[HttpGet("getUser.view")]
|
||||
[HttpPost("getUser.view")]
|
||||
[ProducesResponseType(200)]
|
||||
|
@ -631,6 +617,20 @@ namespace Roadie.Api.Controllers
|
|||
return Content("<subsonic-response xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://subsonic.org/restapi\" status=\"ok\" version=\"1.16.0\" />", "application/xml");
|
||||
}
|
||||
|
||||
[HttpGet("savePlayQueue.view")]
|
||||
[HttpPost("savePlayQueue.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> SavePlayQueue(SubsonicRequest request, string username, string current, long? position)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.SavePlayQueue(request, this.SubsonicUser, current, position);
|
||||
return this.BuildResponse(request, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns albums, artists and songs matching the given search criteria. Supports paging through the result.
|
||||
/// </summary>
|
||||
|
|
|
@ -11,6 +11,7 @@ using Roadie.Library.Models.Pagination;
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using models = Roadie.Library.Models;
|
||||
|
||||
namespace Roadie.Api.Controllers
|
||||
|
@ -47,28 +48,6 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("edit")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> Update(Track track)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
var result = await this.TrackService.UpdateTrack(await this.CurrentUserModel(), track);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> List([FromQuery]PagedRequest request, string inc, bool? doRandomize = false)
|
||||
|
@ -94,5 +73,27 @@ namespace Roadie.Api.Controllers
|
|||
}
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
[HttpPost("edit")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> Update(Track track)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
var result = await this.TrackService.UpdateTrack(await this.CurrentUserModel(), track);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,8 +23,8 @@ namespace Roadie.Api.Controllers
|
|||
public class UserController : EntityControllerBase
|
||||
{
|
||||
private readonly ITokenService TokenService;
|
||||
private IUserService UserService { get; }
|
||||
private IHttpContext RoadieHttpContext { get; }
|
||||
private IUserService UserService { get; }
|
||||
|
||||
public UserController(IUserService userService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, ITokenService tokenService, UserManager<ApplicationUser> userManager, IHttpContext httpContext)
|
||||
: base(cacheManager, configuration, userManager)
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||
<PackageReference Include="Serilog.Sinks.RollingFileAlternate" Version="2.0.9" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.4.0" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.13" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.15" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
Loading…
Add table
Reference in a new issue