mirror of
https://github.com/sphildreth/roadie
synced 2024-11-22 04:03:10 +00:00
resolves #33
This commit is contained in:
parent
df47a9c918
commit
25f4ba2c68
19 changed files with 254 additions and 70 deletions
|
@ -48,9 +48,9 @@ namespace Roadie.Library.Data
|
|||
return $"urn:artist_by_name:{name}";
|
||||
}
|
||||
|
||||
public string ArtistFileFolder(IRoadieSettings configuration)
|
||||
public string ArtistFileFolder(IRoadieSettings configuration, bool createIfNotFound = false)
|
||||
{
|
||||
return FolderPathHelper.ArtistPath(configuration, Id, SortNameValue);
|
||||
return FolderPathHelper.ArtistPath(configuration, Id, SortNameValue, createIfNotFound);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Roadie.Library.Data.Context
|
||||
{
|
||||
public interface IRoadieDbRandomizer
|
||||
{
|
||||
SortedDictionary<int, int> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
Task<SortedDictionary<int, int>> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
SortedDictionary<int, int> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
Task<SortedDictionary<int, int>> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
SortedDictionary<int, int> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
Task<SortedDictionary<int, int>> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
SortedDictionary<int, int> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
Task<SortedDictionary<int, int>> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
SortedDictionary<int, int> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
Task<SortedDictionary<int, int>> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
}
|
||||
}
|
|
@ -109,7 +109,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public override SortedDictionary<int, int> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
var sql = @"SELECT a.id
|
||||
FROM `artist` a
|
||||
|
@ -118,34 +118,34 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
AND {2} = 1)
|
||||
order BY RIGHT(HEX((1 << 24) * (1 + RAND())), 6)
|
||||
LIMIT 0, {0}";
|
||||
var ids = Artists.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToList();
|
||||
var ids = await Artists.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync();
|
||||
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override SortedDictionary<int, int> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
var sql = @"SELECT g.id
|
||||
FROM `genre` g
|
||||
ORDER BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
||||
LIMIT 0, {0}";
|
||||
var ids = Genres.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToList();
|
||||
var ids = await Genres.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync();
|
||||
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override SortedDictionary<int, int> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
var sql = @"SELECT l.id
|
||||
FROM `label` l
|
||||
ORDER BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
||||
LIMIT 0, {0}";
|
||||
var ids = Labels.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToList();
|
||||
var ids = await Labels.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync();
|
||||
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override SortedDictionary<int, int> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
var sql = @"SELECT r.id
|
||||
FROM `release` r
|
||||
|
@ -154,12 +154,12 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
AND {2} = 1)
|
||||
ORDER BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
||||
LIMIT 0, {0}";
|
||||
var ids = Releases.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToList();
|
||||
var ids = await Releases.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync();
|
||||
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override SortedDictionary<int, int> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
var sql = @"SELECT t.id
|
||||
FROM `track` t
|
||||
|
@ -189,7 +189,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
WHERE ut.userId = {1} AND ut.isFavorite = 1) AND {2} = 1) OR {2} = 0)
|
||||
order BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
||||
LIMIT 0, {0}";
|
||||
var ids = Releases.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0", doOnlyRated ? "1" : "0").Select(x => x.Id).ToList();
|
||||
var ids = await Releases.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0", doOnlyRated ? "1" : "0").Select(x => x.Id).ToListAsync();
|
||||
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
|
|
@ -6,15 +6,15 @@ namespace Roadie.Library.Data.Context
|
|||
{
|
||||
public abstract partial class RoadieDbContext : DbContext, IRoadieDbContext
|
||||
{
|
||||
public abstract SortedDictionary<int, int> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
public abstract Task<SortedDictionary<int, int>> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
public abstract SortedDictionary<int, int> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
public abstract Task<SortedDictionary<int, int>> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
public abstract SortedDictionary<int, int> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
public abstract Task<SortedDictionary<int, int>> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
public abstract SortedDictionary<int, int> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
public abstract Task<SortedDictionary<int, int>> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
public abstract SortedDictionary<int, int> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
public abstract Task<SortedDictionary<int, int>> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
public abstract Task<Artist> MostPlayedArtist(int userId);
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ namespace Roadie.Library.Data
|
|||
|
||||
[Column("sortName")] [MaxLength(250)] public string SortName { get; set; }
|
||||
|
||||
public string SortNameValue => string.IsNullOrEmpty(SortName) ? Name : SortName;
|
||||
|
||||
[Column("tags", TypeName = "text")]
|
||||
[MaxLength(65535)]
|
||||
public string Tags { get; set; }
|
||||
|
|
|
@ -113,6 +113,7 @@ namespace Roadie.Library.Models
|
|||
public string Tooltip => Name;
|
||||
|
||||
public UserArtist UserRating { get; set; }
|
||||
public string SortNameValue => string.IsNullOrEmpty(SortName) ? Name : SortName;
|
||||
|
||||
public Artist()
|
||||
{
|
||||
|
|
|
@ -52,5 +52,6 @@ namespace Roadie.Library.Models.Collections
|
|||
|
||||
public CollectionStatistics Statistics { get; set; }
|
||||
public Image Thumbnail { get; set; }
|
||||
public string SortNameValue => string.IsNullOrEmpty(SortName) ? Name : SortName;
|
||||
}
|
||||
}
|
|
@ -41,5 +41,6 @@ namespace Roadie.Library.Models
|
|||
|
||||
public ReleaseGroupingStatistics Statistics { get; set; }
|
||||
public Image Thumbnail { get; set; }
|
||||
public string SortNameValue => string.IsNullOrEmpty(SortName) ? Name : SortName;
|
||||
}
|
||||
}
|
|
@ -81,6 +81,7 @@ namespace Roadie.Library.Models.Releases
|
|||
|
||||
public short TrackCount { get; set; }
|
||||
public UserRelease UserRating { get; set; }
|
||||
public string SortTitleValue => string.IsNullOrEmpty(SortTitle) ? Title : SortTitle;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace Roadie.Library.Utility
|
|||
/// Full path to Artist folder
|
||||
/// </summary>
|
||||
/// <param name="artistSortName">Sort name of Artist to use for folder name</param>
|
||||
public static string ArtistPath(IRoadieSettings configuration, int artistId, string artistSortName)
|
||||
public static string ArtistPath(IRoadieSettings configuration, int artistId, string artistSortName, bool createIfNotFound = false)
|
||||
{
|
||||
SimpleContract.Requires<ArgumentException>(!string.IsNullOrEmpty(artistSortName), "Invalid Artist Sort Name");
|
||||
SimpleContract.Requires<ArgumentException>(configuration.LibraryFolder.Length < MaximumLibraryFolderNameLength, $"Library Folder maximum length is [{ MaximumLibraryFolderNameLength }]");
|
||||
|
@ -76,6 +76,10 @@ namespace Roadie.Library.Utility
|
|||
}
|
||||
artistFolder = Path.Combine(fnSubPart, $"{ artistFolder }{ fnIdPart }");
|
||||
var directoryInfo = new DirectoryInfo(Path.Combine(configuration.LibraryFolder, artistFolder));
|
||||
if(createIfNotFound && !directoryInfo.Exists)
|
||||
{
|
||||
directoryInfo.Create();
|
||||
}
|
||||
return directoryInfo.FullName;
|
||||
}
|
||||
|
||||
|
@ -183,7 +187,7 @@ namespace Roadie.Library.Utility
|
|||
/// <param name="artistFolder">Full path to Artist folder</param>
|
||||
/// <param name="releaseTitle">Title of Release</param>
|
||||
/// <param name="releaseDate">Date of Release</param>
|
||||
public static string ReleasePath(string artistFolder, string releaseTitle, DateTime releaseDate)
|
||||
public static string ReleasePath(string artistFolder, string releaseTitle, DateTime releaseDate, bool createIfNotFound = false)
|
||||
{
|
||||
SimpleContract.Requires<ArgumentException>(!string.IsNullOrEmpty(artistFolder), "Invalid Artist Folder");
|
||||
SimpleContract.Requires<ArgumentException>(artistFolder.Length < MaximumArtistFolderNameLength, $"Artist Folder is longer than maximum allowed [{ MaximumArtistFolderNameLength }]");
|
||||
|
@ -211,6 +215,10 @@ namespace Roadie.Library.Utility
|
|||
}
|
||||
var releasePath = $"[{ releaseDate.ToString("yyyy")}] {releasePathTitle}";
|
||||
var directoryInfo = new DirectoryInfo(Path.Combine(artistFolder, releasePath));
|
||||
if(createIfNotFound && !directoryInfo.Exists)
|
||||
{
|
||||
directoryInfo.Create();
|
||||
}
|
||||
return directoryInfo.FullName;
|
||||
}
|
||||
|
||||
|
|
|
@ -252,7 +252,7 @@ namespace Roadie.Api.Services
|
|||
if (doRandomize ?? false)
|
||||
{
|
||||
var randomLimit = request.Limit ?? roadieUser?.RandomReleaseLimit ?? request.LimitValue;
|
||||
randomArtistData = DbContext.RandomArtistIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly);
|
||||
randomArtistData = await DbContext.RandomArtistIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly);
|
||||
randomArtistIds = randomArtistData.Select(x => x.Value).ToArray();
|
||||
rowCount = DbContext.Artists.Count();
|
||||
}
|
||||
|
@ -592,21 +592,14 @@ namespace Roadie.Api.Services
|
|||
return new OperationResult<bool>(true, $"Artist Not Found [{model.Id}]");
|
||||
}
|
||||
// If artist is being renamed, see if artist already exists with new model supplied name
|
||||
if (artist.Name.ToAlphanumericName() != model.Name.ToAlphanumericName())
|
||||
var artistName = artist.SortNameValue;
|
||||
var artistModelName = model.SortNameValue;
|
||||
if (artistName.ToAlphanumericName() != artistModelName.ToAlphanumericName())
|
||||
{
|
||||
var existingArtist = DbContext.Artists.FirstOrDefault(x => x.Name == model.Name);
|
||||
var existingArtist = DbContext.Artists.FirstOrDefault(x => x.Name == model.Name || x.SortName == model.SortName);
|
||||
if (existingArtist != null)
|
||||
{
|
||||
return new OperationResult<bool>($"Artist already exists with name [{ model.Name }].");
|
||||
}
|
||||
}
|
||||
// If artist sortname is being modified, see if artist already exists with new model supplied sort name
|
||||
if ((artist.SortName?.ToAlphanumericName() ?? string.Empty) != (model.SortName?.ToAlphanumericName() ?? string.Empty))
|
||||
{
|
||||
var existingArtist = DbContext.Artists.FirstOrDefault(x => x.SortName == model.SortName);
|
||||
if (existingArtist != null)
|
||||
{
|
||||
return new OperationResult<bool>($"Artist already exists with sort name [{ model.SortName }].");
|
||||
return new OperationResult<bool>($"Artist already exists `{ existingArtist }` with name [{artistModelName }].");
|
||||
}
|
||||
}
|
||||
try
|
||||
|
|
|
@ -264,12 +264,14 @@ namespace Roadie.Api.Services
|
|||
return new OperationResult<bool>(true, string.Format("Collection Not Found [{0}]", model.Id));
|
||||
}
|
||||
// If collection is being renamed, see if collection already exists with new model supplied name
|
||||
if (collection.Name.ToAlphanumericName() != model.Name.ToAlphanumericName())
|
||||
var collectionName = collection.SortNameValue;
|
||||
var collectionModelName = model.SortNameValue;
|
||||
if (collectionName.ToAlphanumericName() != collectionModelName.ToAlphanumericName())
|
||||
{
|
||||
var existingCollection = DbContext.Collections.FirstOrDefault(x => x.Name == model.Name);
|
||||
var existingCollection = DbContext.Collections.FirstOrDefault(x => x.Name == model.Name || x.SortName == model.SortName);
|
||||
if (existingCollection != null)
|
||||
{
|
||||
return new OperationResult<bool>($"Collection already exists with name [{ model.Name }].");
|
||||
return new OperationResult<bool>($"Collection already exists `{ collection }` with name [{ collectionModelName }].");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public Task<Library.Models.Pagination.PagedResult<GenreList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false)
|
||||
public async Task<Library.Models.Pagination.PagedResult<GenreList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -102,7 +102,7 @@ namespace Roadie.Api.Services
|
|||
if (doRandomize ?? false)
|
||||
{
|
||||
var randomLimit = request.Limit ?? roadieUser?.RandomReleaseLimit ?? request.LimitValue;
|
||||
randomGenreData = DbContext.RandomGenreIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly);
|
||||
randomGenreData = await DbContext.RandomGenreIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly);
|
||||
randomGenreIds = randomGenreData.Select(x => x.Value).ToArray();
|
||||
rowCount = DbContext.Genres.Count();
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
|
||||
sw.Stop();
|
||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<GenreList>
|
||||
return (new Library.Models.Pagination.PagedResult<GenreList>
|
||||
{
|
||||
TotalCount = rowCount.Value,
|
||||
CurrentPage = request.PageValue,
|
||||
|
@ -178,12 +178,15 @@ namespace Roadie.Api.Services
|
|||
return new OperationResult<bool>(true, string.Format("Genre Not Found [{0}]", model.Id));
|
||||
}
|
||||
// If genre is being renamed, see if genre already exists with new model supplied name
|
||||
if (genre.Name.ToAlphanumericName() != model.Name.ToAlphanumericName())
|
||||
var genreName = genre.SortNameValue;
|
||||
var genreModelName = genre.SortNameValue;
|
||||
var didChangeName = !genreName.ToAlphanumericName().Equals(genreModelName.ToAlphanumericName(), StringComparison.OrdinalIgnoreCase);
|
||||
if (didChangeName)
|
||||
{
|
||||
var existingGenre = DbContext.Genres.FirstOrDefault(x => x.Name == model.Name);
|
||||
var existingGenre = DbContext.Genres.FirstOrDefault(x => x.Name == model.Name || x.SortName == model.SortName);
|
||||
if (existingGenre != null)
|
||||
{
|
||||
return new OperationResult<bool>($"Genre already exists with name [{ model.Name }].");
|
||||
return new OperationResult<bool>($"Genre already exists `{ existingGenre }` with name [{ genreModelName }].");
|
||||
}
|
||||
}
|
||||
try
|
||||
|
@ -196,10 +199,11 @@ namespace Roadie.Api.Services
|
|||
alt.Add(specialGenreName);
|
||||
}
|
||||
genre.AlternateNames = alt.ToDelimitedList();
|
||||
genre.Description = model.Description;
|
||||
genre.IsLocked = model.IsLocked;
|
||||
var oldPathToImage = genre.PathToImage(Configuration);
|
||||
var didChangeName = genre.Name != model.Name;
|
||||
genre.Name = model.Name;
|
||||
genre.NormalizedName = model.NormalizedName;
|
||||
genre.SortName = model.SortName;
|
||||
genre.Status = SafeParser.ToEnum<Statuses>(model.Status);
|
||||
genre.Tags = model.TagsList.ToDelimitedList();
|
||||
|
|
|
@ -7,8 +7,17 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface IStatisticsService
|
||||
{
|
||||
Task<OperationResult<LibraryStats>> LibraryStatistics();
|
||||
Task<OperationResult<LibraryStats>> LibraryStatistics();
|
||||
|
||||
Task<OperationResult<IEnumerable<DateAndCount>>> ArtistsByDate();
|
||||
|
||||
Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDate();
|
||||
|
||||
Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDecade();
|
||||
|
||||
Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByDate();
|
||||
|
||||
Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByUser();
|
||||
|
||||
}
|
||||
}
|
|
@ -111,7 +111,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public Task<Library.Models.Pagination.PagedResult<LabelList>> List(User roadieUser, PagedRequest request,
|
||||
public async Task<Library.Models.Pagination.PagedResult<LabelList>> List(User roadieUser, PagedRequest request,
|
||||
bool? doRandomize = false)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
|
@ -134,7 +134,7 @@ namespace Roadie.Api.Services
|
|||
if (doRandomize ?? false)
|
||||
{
|
||||
var randomLimit = request.Limit ?? roadieUser?.RandomReleaseLimit ?? request.LimitValue;
|
||||
randomLabelData = DbContext.RandomLabelIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly);
|
||||
randomLabelData = await DbContext.RandomLabelIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly);
|
||||
randomLabelIds = randomLabelData.Select(x => x.Value).ToArray();
|
||||
rowCount = DbContext.Labels.Count();
|
||||
}
|
||||
|
@ -188,14 +188,14 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
|
||||
sw.Stop();
|
||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<LabelList>
|
||||
return new Library.Models.Pagination.PagedResult<LabelList>
|
||||
{
|
||||
TotalCount = rowCount.Value,
|
||||
CurrentPage = request.PageValue,
|
||||
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Rows = rows
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> MergeLabelsIntoLabel(ApplicationUser user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge)
|
||||
|
@ -274,12 +274,16 @@ namespace Roadie.Api.Services
|
|||
return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", model.Id));
|
||||
}
|
||||
// If label is being renamed, see if label already exists with new model supplied name
|
||||
if (label.Name.ToAlphanumericName() != model.Name.ToAlphanumericName())
|
||||
var labelName = label.SortNameValue;
|
||||
var labelModelName = model.SortNameValue;
|
||||
var oldPathToImage = label.PathToImage(Configuration);
|
||||
var didChangeName = !labelName.ToAlphanumericName().Equals(labelModelName.ToAlphanumericName(), StringComparison.OrdinalIgnoreCase);
|
||||
if (didChangeName)
|
||||
{
|
||||
var existingLabel = DbContext.Labels.FirstOrDefault(x => x.Name == model.Name);
|
||||
var existingLabel = DbContext.Labels.FirstOrDefault(x => x.Name == model.Name || x.SortName == model.SortName );
|
||||
if (existingLabel != null)
|
||||
{
|
||||
return new OperationResult<bool>($"Label already exists with name [{ model.Name }].");
|
||||
return new OperationResult<bool>($"Label already exists `{ existingLabel }` with name [{ labelModelName }].");
|
||||
}
|
||||
}
|
||||
try
|
||||
|
@ -297,8 +301,6 @@ namespace Roadie.Api.Services
|
|||
label.EndDate = model.EndDate;
|
||||
label.IsLocked = model.IsLocked;
|
||||
label.MusicBrainzId = model.MusicBrainzId;
|
||||
var oldPathToImage = label.PathToImage(Configuration);
|
||||
var didChangeName = label.Name != model.Name;
|
||||
label.Name = model.Name;
|
||||
label.Profile = model.Profile;
|
||||
label.SortName = model.SortName;
|
||||
|
|
|
@ -397,7 +397,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public Task<Library.Models.Pagination.PagedResult<ReleaseList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, IEnumerable<string> includes = null)
|
||||
public async Task<Library.Models.Pagination.PagedResult<ReleaseList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, IEnumerable<string> includes = null)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -486,7 +486,7 @@ namespace Roadie.Api.Services
|
|||
if (doRandomize ?? false)
|
||||
{
|
||||
var randomLimit = request.Limit ?? roadieUser?.RandomReleaseLimit ?? request.LimitValue;
|
||||
randomReleaseData = DbContext.RandomReleaseIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly);
|
||||
randomReleaseData = await DbContext.RandomReleaseIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly);
|
||||
randomReleaseIds = randomReleaseData.Select(x => x.Value).ToArray();
|
||||
rowCount = DbContext.Releases.Count();
|
||||
}
|
||||
|
@ -754,14 +754,14 @@ namespace Roadie.Api.Services
|
|||
|
||||
if (request.FilterFavoriteOnly) rows = rows.OrderBy(x => x.UserRating.Rating).ToArray();
|
||||
sw.Stop();
|
||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<ReleaseList>
|
||||
return new Library.Models.Pagination.PagedResult<ReleaseList>
|
||||
{
|
||||
TotalCount = rowCount.Value,
|
||||
CurrentPage = request.PageValue,
|
||||
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Rows = rows
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> MergeReleases(ApplicationUser user, Guid releaseToMergeId, Guid releaseToMergeIntoId, bool addAsMedia)
|
||||
|
@ -1534,12 +1534,16 @@ namespace Roadie.Api.Services
|
|||
return new OperationResult<bool>(true, string.Format("Release Not Found [{0}]", model.Id));
|
||||
}
|
||||
// If release is being renamed, see if release already exists for artist with new model supplied name
|
||||
if (release.Title.ToAlphanumericName() != model.Title.ToAlphanumericName())
|
||||
var releaseTitle = release.SortTitleValue;
|
||||
var releaseModelTitle = model.SortTitleValue;
|
||||
if (releaseTitle.ToAlphanumericName() != releaseModelTitle.ToAlphanumericName())
|
||||
{
|
||||
var existingRelease = DbContext.Releases.FirstOrDefault(x => x.Title == model.Title && x.ArtistId == release.ArtistId);
|
||||
var existingRelease = DbContext.Releases.FirstOrDefault(x => x.Id != release.Id &&
|
||||
(x.Title == releaseModelTitle || x.SortTitle == releaseModelTitle) &&
|
||||
x.ArtistId == release.ArtistId);
|
||||
if (existingRelease != null)
|
||||
{
|
||||
return new OperationResult<bool>($"Release already exists for Artist with title [{ model.Title }].");
|
||||
return new OperationResult<bool>($"Release already exists `{ existingRelease }` for Artist with title [{ releaseModelTitle }].");
|
||||
}
|
||||
}
|
||||
try
|
||||
|
|
|
@ -66,6 +66,38 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DateAndCount>>> ArtistsByDate()
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var result = new List<DateAndCount>();
|
||||
var dateInfos = (from r in DbContext.Artists
|
||||
orderby r.CreatedDate
|
||||
select r.CreatedDate)
|
||||
.ToArray()
|
||||
.GroupBy(x => x.ToString("yyyy-MM-dd"))
|
||||
.Select(x => new
|
||||
{
|
||||
date = x.Key,
|
||||
count = x.Count()
|
||||
});
|
||||
foreach (var dateInfo in dateInfos)
|
||||
{
|
||||
result.Add(new DateAndCount
|
||||
{
|
||||
Date = dateInfo.date,
|
||||
Count = dateInfo.count
|
||||
});
|
||||
}
|
||||
sw.Stop();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
|
||||
{
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
IsSuccess = result != null,
|
||||
Data = result
|
||||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDate()
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
|
@ -97,5 +129,112 @@ namespace Roadie.Api.Services
|
|||
Data = result
|
||||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByUser()
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var result = new List<DateAndCount>();
|
||||
var dateInfos = (from r in DbContext.UserTracks
|
||||
join u in DbContext.Users on r.UserId equals u.Id
|
||||
select new { u.UserName, r.PlayedCount })
|
||||
.ToArray()
|
||||
.GroupBy(x => x.UserName)
|
||||
.Select(x => new
|
||||
{
|
||||
username = x.Key,
|
||||
count = x.Count()
|
||||
});
|
||||
foreach (var dateInfo in dateInfos)
|
||||
{
|
||||
result.Add(new DateAndCount
|
||||
{
|
||||
Date = dateInfo.username,
|
||||
Count = dateInfo.count
|
||||
});
|
||||
}
|
||||
sw.Stop();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
|
||||
{
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
IsSuccess = result != null,
|
||||
Data = result
|
||||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByDate()
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var result = new List<DateAndCount>();
|
||||
var dateInfos = (from r in DbContext.UserTracks
|
||||
orderby r.LastPlayed
|
||||
select r.LastPlayed ?? r.CreatedDate)
|
||||
.ToArray()
|
||||
.GroupBy(x => x.ToString("yyyy-MM-dd"))
|
||||
.Select(x => new
|
||||
{
|
||||
date = x.Key,
|
||||
count = x.Count()
|
||||
});
|
||||
foreach (var dateInfo in dateInfos)
|
||||
{
|
||||
result.Add(new DateAndCount
|
||||
{
|
||||
Date = dateInfo.date,
|
||||
Count = dateInfo.count
|
||||
});
|
||||
}
|
||||
sw.Stop();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
|
||||
{
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
IsSuccess = result != null,
|
||||
Data = result
|
||||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDecade()
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var result = new List<DateAndCount>();
|
||||
var decadeInfos = (from r in DbContext.Releases
|
||||
orderby r.ReleaseDate
|
||||
select r.ReleaseDate ?? r.CreatedDate)
|
||||
.ToArray()
|
||||
.GroupBy(x => x.ToString("yyyy"))
|
||||
.Select(x => new
|
||||
{
|
||||
year = SafeParser.ToNumber<int>(x.Key),
|
||||
count = x.Count()
|
||||
});
|
||||
|
||||
var decadeInterval = 10;
|
||||
var startingDecade = (decadeInfos.Min(x => x.year) / 10) * 10;
|
||||
var endingDecade = (decadeInfos.Max(x => x.year) / 10) * 10;
|
||||
for (int decade = startingDecade; decade <= endingDecade; decade += decadeInterval)
|
||||
{
|
||||
var endOfDecade = decade + 9;
|
||||
var count = decadeInfos.Where(x => x.year >= decade && x.year <= endOfDecade).Sum(x => x.count);
|
||||
if (count > 0)
|
||||
{
|
||||
result.Add(new DateAndCount
|
||||
{
|
||||
Date = decade.ToString(),
|
||||
Count = count
|
||||
});
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
|
||||
{
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
IsSuccess = result != null,
|
||||
Data = result
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -199,7 +199,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public Task<Library.Models.Pagination.PagedResult<TrackList>> List(PagedRequest request, User roadieUser, bool? doRandomize = false, Guid? releaseId = null)
|
||||
public async Task<Library.Models.Pagination.PagedResult<TrackList>> List(PagedRequest request, User roadieUser, bool? doRandomize = false, Guid? releaseId = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -289,7 +289,7 @@ namespace Roadie.Api.Services
|
|||
if (doRandomize ?? false)
|
||||
{
|
||||
var randomLimit = roadieUser?.RandomReleaseLimit ?? request.LimitValue;
|
||||
randomTrackData = DbContext.RandomTrackIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly);
|
||||
randomTrackData = await DbContext.RandomTrackIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly);
|
||||
randomTrackIds = randomTrackData.Select(x => x.Value).ToArray();
|
||||
rowCount = DbContext.Releases.Count();
|
||||
}
|
||||
|
@ -623,22 +623,22 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
|
||||
sw.Stop();
|
||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<TrackList>
|
||||
return new Library.Models.Pagination.PagedResult<TrackList>
|
||||
{
|
||||
TotalCount = rowCount ?? 0,
|
||||
CurrentPage = request.PageValue,
|
||||
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Rows = rows
|
||||
});
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Error In List, Request [{0}], User [{1}]", JsonConvert.SerializeObject(request), roadieUser);
|
||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<TrackList>
|
||||
return new Library.Models.Pagination.PagedResult<TrackList>
|
||||
{
|
||||
Message = "An Error has occured"
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,8 +59,24 @@ namespace Roadie.Api.Controllers
|
|||
[AllowAnonymous]
|
||||
public IActionResult Ping() => Ok("pong");
|
||||
|
||||
[HttpGet("artistsByDate")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ArtistsByDate() => Ok(await StatisticsService.ArtistsByDate());
|
||||
|
||||
[HttpGet("releasesByDate")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ReleasesByDate() => Ok(await StatisticsService.ReleasesByDate());
|
||||
|
||||
[HttpGet("releasesByDecade")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ReleasesByDecade() => Ok(await StatisticsService.ReleasesByDecade());
|
||||
|
||||
[HttpGet("songsPlayedByDate")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> SongsPlayedByDate() => Ok(await StatisticsService.SongsPlayedByDate());
|
||||
|
||||
[HttpGet("songsPlayedByUser")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> SongsPlayedByUser() => Ok(await StatisticsService.SongsPlayedByUser());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue