Playlist get work.

This commit is contained in:
Steven Hildreth 2018-12-09 11:58:31 -06:00
parent 95e85cf3e4
commit f0e6fa53ef
13 changed files with 234 additions and 62 deletions

View file

@ -29,33 +29,22 @@ namespace Roadie.Api.Controllers
this.PlaylistService = playlistService;
}
//[EnableQuery]
//public IActionResult Get()
//{
// return Ok(this._RoadieDbContext.Tracks.ProjectToType<models.Track>());
//}
//[HttpGet("{id}")]
//[ProducesResponseType(200)]
//[ProducesResponseType(404)]
//public IActionResult Get(Guid id)
//{
// var key = id.ToString();
// var result = this._cacheManager.Get<models.Track>(key, () =>
// {
// var d = this._RoadieDbContext.Tracks.FirstOrDefault(x => x.RoadieId == id);
// if (d != null)
// {
// return d.Adapt<models.Track>();
// }
// return null;
// }, key);
// if (result == null)
// {
// return NotFound();
// }
// 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)]

View file

@ -31,12 +31,6 @@ namespace Roadie.Api.Controllers
this.ReleaseService = releaseService;
}
//[EnableQuery]
//public IActionResult Get()
//{
// return Ok(this._RoadieDbContext.Releases.ProjectToType<models.Releases.Release>());
//}
[HttpGet("{id}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]

View file

@ -25,8 +25,7 @@ namespace Roadie.Api.Services
data.IRoadieDbContext context,
ICacheManager cacheManager,
ILogger<BookmarkService> logger,
ICollectionService collectionService,
IPlaylistService playlistService)
ICollectionService collectionService)
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
{
}

View file

@ -1,13 +1,17 @@
using Roadie.Library.Models.Pagination;
using Roadie.Library;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Playlists;
using Roadie.Library.Models.Users;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Roadie.Api.Services
{
public interface IPlaylistService
{
Task<OperationResult<Playlist>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<PagedResult<PlaylistList>> List(PagedRequest request, User roadieUser = null);
}
}

View file

@ -1,10 +1,16 @@
using Microsoft.Extensions.Logging;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Roadie.Library;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Encoding;
using Roadie.Library.Enums;
using Roadie.Library.Extensions;
using Roadie.Library.Models;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Playlists;
using Roadie.Library.Models.Releases;
using Roadie.Library.Models.Users;
using Roadie.Library.Utility;
using System;
@ -19,16 +25,140 @@ namespace Roadie.Api.Services
{
public class PlaylistService : ServiceBase, IPlaylistService
{
private IBookmarkService BookmarkService { get; } = null;
public PlaylistService(IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext dbContext,
ICacheManager cacheManager,
ILogger<PlaylistService> logger)
ILogger<PlaylistService> logger,
IBookmarkService bookmarkService)
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
{
this.BookmarkService = bookmarkService;
}
public async Task<OperationResult<Playlist>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null)
{
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = string.Format("urn:playlist_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
var result = await this.CacheManager.GetAsync<OperationResult<Playlist>>(cacheKey, async () =>
{
return await this.PlaylistByIdAction(id, includes);
}, data.Artist.CacheRegionUrn(id));
sw.Stop();
if (result?.Data != null && roadieUser != null)
{
result.Data.UserCanEdit = result.Data.Maintainer.Id == roadieUser.UserId || roadieUser.IsAdmin;
var userBookmarkResult = await this.BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Playlist);
if (userBookmarkResult.IsSuccess)
{
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Text == result.Data.Id.ToString()) != null;
}
}
return new OperationResult<Playlist>(result.Messages)
{
Data = result?.Data,
IsNotFoundResult = result?.IsNotFoundResult ?? false,
Errors = result?.Errors,
IsSuccess = result?.IsSuccess ?? false,
OperationTime = sw.ElapsedMilliseconds
};
}
private async Task<OperationResult<Playlist>> PlaylistByIdAction(Guid id, IEnumerable<string> includes = null)
{
var sw = Stopwatch.StartNew();
sw.Start();
var playlist = this.GetPlaylist(id);
if (playlist == null)
{
return new OperationResult<Playlist>(true, string.Format("Playlist Not Found [{0}]", id));
}
var result = playlist.Adapt<Playlist>();
result.AlternateNames = playlist.AlternateNames;
result.Tags = playlist.Tags;
result.URLs = playlist.URLs;
var maintainer = this.DbContext.Users.Include(x => x.UserRoles).Include("UserRoles.Role").FirstOrDefault(x => x.Id == playlist.UserId);
result.Maintainer = UserList.FromDataUser(maintainer, this.MakeUserThumbnailImage(maintainer.RoadieId));
result.Thumbnail = this.MakePlaylistThumbnailImage(playlist.RoadieId);
result.MediumThumbnail = base.MakeThumbnailImage(id, "playlist", this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height);
if (includes != null && includes.Any())
{
var playlistTracks = (from pl in this.DbContext.Playlists
join pltr in this.DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
join t in this.DbContext.Tracks on pltr.TrackId equals t.Id
where pl.Id == playlist.Id
select new { t, pltr });
if (includes.Contains("stats"))
{
result.Statistics = new Library.Models.Statistics.ReleaseGroupingStatistics
{
ReleaseCount = result.ReleaseCount,
TrackCount = result.TrackCount,
TrackSize = result.DurationTime,
FileSize = playlistTracks.Sum(x => (long?)x.t.FileSize).ToFileSize()
};
}
if (includes.Contains("tracks"))
{
result.Tracks = (from plt in playlistTracks
join rm in this.DbContext.ReleaseMedias on plt.t.ReleaseMediaId equals rm.Id
join r in this.DbContext.Releases on rm.ReleaseId equals r.Id
join releaseArtist in this.DbContext.Artists on r.ArtistId equals releaseArtist.Id
join trackArtist in this.DbContext.Artists on plt.t.ArtistId equals trackArtist.Id into tas
from trackArtist in tas.DefaultIfEmpty()
select new PlaylistTrack
{
ListNumber = plt.pltr.ListNumber,
Track = new TrackList
{
DatabaseId = plt.t.Id,
Id = plt.t.RoadieId,
Track = new DataToken
{
Text = plt.t.Title,
Value = plt.t.RoadieId.ToString()
},
Release = ReleaseList.FromDataRelease(r, releaseArtist, this.HttpContext.BaseUrl, this.MakeArtistThumbnailImage(releaseArtist.RoadieId), this.MakeReleaseThumbnailImage(r.RoadieId)),
LastPlayed = plt.t.LastPlayed,
Artist = ArtistList.FromDataArtist(releaseArtist, this.MakeArtistThumbnailImage(releaseArtist.RoadieId)),
TrackArtist = trackArtist == null ? null : ArtistList.FromDataArtist(trackArtist, this.MakeArtistThumbnailImage(trackArtist.RoadieId)),
TrackNumber = plt.t.TrackNumber,
MediaNumber = rm.MediaNumber,
CreatedDate = plt.t.CreatedDate,
LastUpdated = plt.t.LastUpdated,
Duration = plt.t.Duration,
FileSize = plt.t.FileSize,
ReleaseDate = r.ReleaseDate,
PlayedCount = plt.t.PlayedCount,
Rating = plt.t.Rating,
Title = plt.t.Title,
TrackPlayUrl = $"{ this.HttpContext.BaseUrl }/play/track/{ plt.t.RoadieId }.mp3",
Thumbnail = this.MakeTrackThumbnailImage(plt.t.RoadieId)
}
}).ToArray();
}
}
sw.Stop();
return new OperationResult<Playlist>
{
Data = result,
IsSuccess = result != null,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<Library.Models.Pagination.PagedResult<PlaylistList>> List(PagedRequest request, User roadieUser = null)
{
var sw = new Stopwatch();
@ -62,16 +192,11 @@ namespace Roadie.Api.Services
var result = (from pl in this.DbContext.Playlists
join u in this.DbContext.Users on pl.UserId equals u.Id
let duration = (from plt in this.DbContext.PlaylistTracks
join t in this.DbContext.Tracks on plt.TrackId equals t.Id
where plt.PlayListId == pl.Id
select t.Duration).Sum()
where (request.FilterToPlaylistId == null || pl.RoadieId == request.FilterToPlaylistId)
where (request.FilterToArtistId == null || playlistWithArtistTrackIds.Contains(pl.Id))
where (request.FilterToReleaseId == null || playlistReleaseTrackIds.Contains(pl.Id))
where ((roadieUser == null && pl.IsPublic) || (roadieUser != null && u.RoadieId == roadieUser.UserId || pl.IsPublic))
where (request.FilterValue.Length == 0 || (request.FilterValue.Length > 0 && (
pl.Name != null && pl.Name.Contains(request.FilterValue))
where (request.FilterValue.Length == 0 || (request.FilterValue.Length > 0 && (pl.Name != null && pl.Name.Contains(request.FilterValue))
))
select new PlaylistList
{
@ -88,7 +213,8 @@ namespace Roadie.Api.Services
},
PlaylistCount = this.DbContext.PlaylistTracks.Where(x => x.PlayListId == pl.Id).Count(),
IsPublic = pl.IsPublic,
Duration = duration,
Duration = pl.Duration,
TrackCount = pl.TrackCount,
CreatedDate = pl.CreatedDate,
LastUpdated = pl.LastUpdated,
UserThumbnail = MakeUserThumbnailImage(u.RoadieId),

View file

@ -159,6 +159,7 @@ namespace Roadie.Api.Services
}, data.Release.CacheRegionUrn(id));
}
/// <summary>
/// Get Track by Subsonic Id ("T:guid")
/// </summary>

View file

@ -228,6 +228,8 @@ namespace Roadie.Api.Services
var sw = new Stopwatch();
sw.Start();
int? rowCount = null;
IQueryable<int> favoriteTrackIds = (new int[0]).AsQueryable();
if (request.FilterFavoriteOnly)
{
@ -241,7 +243,7 @@ namespace Roadie.Api.Services
int[] playlistTrackIds = new int[0];
if (request.FilterToPlaylistId.HasValue)
{
playListTrackPositions = (from plt in this.DbContext.PlaylistTracks
var playlistTrackInfos = (from plt in this.DbContext.PlaylistTracks
join p in this.DbContext.Playlists on plt.PlayListId equals p.Id
join t in this.DbContext.Tracks on plt.TrackId equals t.Id
where p.RoadieId == request.FilterToPlaylistId.Value
@ -250,7 +252,10 @@ namespace Roadie.Api.Services
{
plt.ListNumber,
t.Id
}).Skip(request.SkipValue).Take(request.LimitValue).ToDictionary(x => x.Id, x => x.ListNumber);
});
rowCount = playlistTrackInfos.Count();
playListTrackPositions = playlistTrackInfos.Skip(request.SkipValue).Take(request.LimitValue).ToDictionary(x => x.Id, x => x.ListNumber);
playlistTrackIds = playListTrackPositions.Select(x => x.Key).ToArray();
request.Sort = "TrackNumber";
request.Order = "ASC";
@ -434,7 +439,7 @@ namespace Roadie.Api.Services
});
string sortBy = null;
var rowCount = result.Count();
rowCount = rowCount ?? result.Count();
TrackList[] rows = null;
if (request.Action == User.ActionKeyUserRated)
@ -491,7 +496,7 @@ namespace Roadie.Api.Services
sw.Stop();
return new Library.Models.Pagination.PagedResult<TrackList>
{
TotalCount = rowCount,
TotalCount = rowCount ?? 0,
CurrentPage = request.PageValue,
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
OperationTime = sw.ElapsedMilliseconds,

View file

@ -8,6 +8,9 @@ namespace Roadie.Library.Data
[Table("playlist")]
public partial class Playlist : NamedEntityBase
{
[NotMapped]
public new string SortName { get; set; }
[Column("Description")]
[MaxLength(1000)]
public string Description { get; set; }
@ -21,5 +24,14 @@ namespace Roadie.Library.Data
[Column("userId")]
public int? UserId { get; set; }
[Column("duration")]
public int? Duration { get; set; } // TODO update this on playlist edit
[Column("trackCount")]
public short TrackCount { get; set; } // TODO update this on playlist edit
[Column("releaseCount")]
public short ReleaseCount { get; set; } // TODO update this on playlist edit
}
}

View file

@ -1,4 +1,6 @@
using Roadie.Library.Models.Statistics;
using Mapster;
using Roadie.Library.Models.Statistics;
using Roadie.Library.Models.Users;
using System;
using System.Collections.Generic;
using System.Text;
@ -6,23 +8,38 @@ using System.Text;
namespace Roadie.Library.Models.Playlists
{
[Serializable]
public class Playlist
public class Playlist : EntityModelBase
{
public const string DefaultIncludes = "stats";
public bool IsPublic { get; set; }
/// <summary>
/// If true then a system generated playlist - like top 20 played songs last 30 days
/// </summary>
public bool IsSystemGenerated { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Guid UserId { get; set; }
public UserList Maintainer { get; set; }
public IEnumerable<PlaylistTrack> Tracks { get; set; }
public IEnumerable<string> Urls { get; set; }
public IEnumerable<string> Tags { get; set; }
public int? PlaylistCount { get; set; }
public string ThumbnailUrl { get; set; }
public ReleaseGroupingStatistics Stats { get; set; }
public string PlaylistPlayUrl { get; set; }
public ReleaseGroupingStatistics Statistics { get; set; }
public bool UserCanEdit { get; set; }
public string UrlsTokenfield { get; set; }
public string TagsTokenfield { get; set; }
public Image Thumbnail { get; set; }
public string BookmarkRoadieId { get; internal set; }
public Image MediumThumbnail { get; set; }
public short? TrackCount { get; set; }
public short? ReleaseCount { get; set; }
public int? Duration { get; set; }
public string DurationTime
{
get
{
if (!this.Duration.HasValue)
{
return "--:--";
}
return TimeSpan.FromSeconds(this.Duration.Value / 1000).ToString(@"dd\.hh\:mm\:ss");
}
}
}
}

View file

@ -26,5 +26,7 @@ namespace Roadie.Library.Models.Playlists
}
}
public short TrackCount { get; set; }
}
}

View file

@ -7,7 +7,7 @@ namespace Roadie.Library.Models.Playlists
[Serializable]
public class PlaylistTrack
{
public Track Track { get; set; }
public TrackList Track { get; set; }
public int ListNumber { get; set; }
}
}

View file

@ -14,6 +14,6 @@ namespace Roadie.Library.Models.Statistics
public int? ReleaseMediaCount { get; set; }
public int? TrackCount { get; set; }
public int? TrackPlayedCount { get; set; }
public string TrackTime { get; set; }
public string TrackSize { get; set; }
}
}

View file

@ -2,6 +2,7 @@
using Roadie.Library.Models.Statistics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Roadie.Library.Models.Users
@ -26,5 +27,27 @@ namespace Roadie.Library.Models.Users
public bool? IsPrivate { get; set; }
public UserStatistics Statistics { get; set; }
public static UserList FromDataUser(Identity.ApplicationUser user, Image thumbnail)
{
return new UserList
{
DatabaseId = user.Id,
Id = user.RoadieId,
User = new DataToken
{
Text = user.UserName,
Value = user.RoadieId.ToString()
},
IsEditor = user.UserRoles.Any(x => x.Role.Name == "Editor"),
IsPrivate = user.IsPrivate,
Thumbnail = thumbnail,
CreatedDate = user.CreatedDate,
LastUpdated = user.LastUpdated,
RegisteredDate = user.RegisteredOn,
LastLoginDate = user.LastLogin,
LastApiAccessDate = user.LastApiAccess
};
}
}
}