diff --git a/RoadieApi/Controllers/PlayController.cs b/RoadieApi/Controllers/PlayController.cs index 71dbb43..92601c8 100644 --- a/RoadieApi/Controllers/PlayController.cs +++ b/RoadieApi/Controllers/PlayController.cs @@ -34,7 +34,8 @@ namespace Roadie.Api.Controllers [HttpGet("track/{id}")] public async Task StreamTrack(Guid id) { - var track = await this.TrackService.ById(await this.CurrentUserModel(), id, null); + var user = await this.CurrentUserModel(); + var track = await this.TrackService.ById(user, id, null); if (track == null || track.IsNotFoundResult) { Response.StatusCode = (int)HttpStatusCode.NotFound; @@ -61,8 +62,8 @@ namespace Roadie.Api.Controllers Response.Headers.Add("Cache-Control", info.Data.CacheControl); Response.Headers.Add("Expires", info.Data.Expires); var stream = new MemoryStream(info.Data.Bytes); - await this.PlayActivityService.CreatePlayActivity(await this.CurrentUserModel(), info.Data); - this._logger.LogInformation($"StreamTrack [{ info.Data.ToString() }]"); + var playListUser = await this.PlayActivityService.CreatePlayActivity(user, info.Data); + this._logger.LogInformation($"StreamTrack PlayActivity `{ playListUser }`, StreamInfo `{ info.Data.ToString() }`"); return new FileStreamResult(stream, info.Data.ContentType) { FileDownloadName = info.Data.FileName diff --git a/RoadieApi/Hubs/PlayActivityHub.cs b/RoadieApi/Hubs/PlayActivityHub.cs new file mode 100644 index 0000000..05afde5 --- /dev/null +++ b/RoadieApi/Hubs/PlayActivityHub.cs @@ -0,0 +1,17 @@ +using Microsoft.AspNetCore.SignalR; +using Roadie.Library.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Roadie.Api.Hubs +{ + public class PlayActivityHub : Hub + { + public async Task SendActivity(PlayActivityList playActivity) + { + await Clients.All.SendAsync("PlayActivity", playActivity); + } + } +} diff --git a/RoadieApi/Roadie.Api.csproj b/RoadieApi/Roadie.Api.csproj index 052ecca..2a806dc 100644 --- a/RoadieApi/Roadie.Api.csproj +++ b/RoadieApi/Roadie.Api.csproj @@ -11,6 +11,7 @@ + diff --git a/RoadieApi/Services/IPlayActivityService.cs b/RoadieApi/Services/IPlayActivityService.cs index 8f3c22c..600d102 100644 --- a/RoadieApi/Services/IPlayActivityService.cs +++ b/RoadieApi/Services/IPlayActivityService.cs @@ -10,6 +10,6 @@ namespace Roadie.Api.Services { Task> List(PagedRequest request, User roadieUser = null); - Task> CreatePlayActivity(User roadieUser, TrackStreamInfo streamInfo); + Task> CreatePlayActivity(User roadieUser, TrackStreamInfo streamInfo); } } \ No newline at end of file diff --git a/RoadieApi/Services/PlayActivityService.cs b/RoadieApi/Services/PlayActivityService.cs index 0a3d1b4..506986c 100644 --- a/RoadieApi/Services/PlayActivityService.cs +++ b/RoadieApi/Services/PlayActivityService.cs @@ -1,5 +1,8 @@ using Mapster; +using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Roadie.Api.Hubs; using Roadie.Library; using Roadie.Library.Caching; using Roadie.Library.Configuration; @@ -20,14 +23,18 @@ namespace Roadie.Api.Services { public class PlayActivityService : ServiceBase, IPlayActivityService { + protected IHubContext PlayActivityHub { get; } + public PlayActivityService(IRoadieSettings configuration, IHttpEncoder httpEncoder, IHttpContext httpContext, data.IRoadieDbContext dbContext, ICacheManager cacheManager, - ILogger logger) + ILogger logger, + IHubContext playHubContext) : base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext) { + this.PlayActivityHub = playHubContext; } public async Task> List(PagedRequest request, User roadieUser = null) @@ -107,23 +114,23 @@ namespace Roadie.Api.Services return new Library.Models.Pagination.PagedResult(); } - public async Task> CreatePlayActivity(User roadieUser, TrackStreamInfo streamInfo) + public async Task> CreatePlayActivity(User roadieUser, TrackStreamInfo streamInfo) { var sw = Stopwatch.StartNew(); var track = this.GetTrack(streamInfo.Track.Value); if (track == null) { - return new OperationResult($"CreatePlayActivity: Unable To Find Track [{ streamInfo.Track.Value }]"); + return new OperationResult($"CreatePlayActivity: Unable To Find Track [{ streamInfo.Track.Value }]"); } if (!track.IsValid) { - return new OperationResult($"CreatePlayActivity: Invalid Track. Track Id [{streamInfo.Track.Value}], FilePath [{track.FilePath}], Filename [{track.FileName}]"); + return new OperationResult($"CreatePlayActivity: Invalid Track. Track Id [{streamInfo.Track.Value}], FilePath [{track.FilePath}], Filename [{track.FileName}]"); } var user = this.GetUser(roadieUser.UserId); if (user == null) { - return new OperationResult($"CreatePlayActivity: Unable To Find User [{ roadieUser.UserId }]"); + return new OperationResult($"CreatePlayActivity: Unable To Find User [{ roadieUser.UserId }]"); } var now = DateTime.UtcNow; track.PlayedCount = (track.PlayedCount ?? 0) + 1; @@ -145,53 +152,60 @@ namespace Roadie.Api.Services this.CacheManager.ClearRegion(track.ReleaseMedia.Release.CacheRegion); this.CacheManager.ClearRegion(track.ReleaseMedia.Release.Artist.CacheRegion); - // TODO publish with SignalR + var pl = new PlayActivityList + { + Artist = new DataToken + { + Text = track.ReleaseMedia.Release.Artist.Name, + Value = track.ReleaseMedia.Release.Artist.RoadieId.ToString() + }, + TrackArtist = track.TrackArtist == null ? null : new DataToken + { + Text = track.TrackArtist.Name, + Value = track.TrackArtist.RoadieId.ToString() + }, + Release = new DataToken + { + Text = track.ReleaseMedia.Release.Title, + Value = track.ReleaseMedia.Release.RoadieId.ToString() + }, + Track = new DataToken + { + Text = track.Title, + Value = track.RoadieId.ToString() + }, + User = new DataToken + { + Text = roadieUser.UserName, + Value = roadieUser.UserId.ToString() + }, + PlayedDateDateTime = userTrack.LastPlayed, + ReleasePlayUrl = $"{ this.HttpContext.BaseUrl }/play/release/{ track.ReleaseMedia.Release.RoadieId}", + Rating = track.Rating, + UserRating = userTrack.Rating, + TrackPlayUrl = $"{ this.HttpContext.BaseUrl }/play/track/{ track.RoadieId}", + ArtistThumbnail = this.MakeArtistThumbnailImage(track.TrackArtist != null ? track.TrackArtist.RoadieId : track.ReleaseMedia.Release.Artist.RoadieId), + ReleaseThumbnail = this.MakeReleaseThumbnailImage(track.ReleaseMedia.Release.RoadieId), + UserThumbnail = this.MakeUserThumbnailImage(roadieUser.UserId) + }; - //if (!this.RoadieUser.isPrivate ?? false) - //{ - // try - // { - // var hub = GlobalHost.ConnectionManager.GetHubContext(); - // var releaseArtist = track.releasemedia.release.artist; - // artist trackArtist = track.artistId == null ? null : context.artists.FirstOrDefault(x => x.id == track.artistId); - // hub.Clients.All.PlayActivity(new PlayActivityListModel - // { - // releaseTitle = track.releasemedia.release.title, - // playedDateDateTime = userTrack.lastPlayed, - // userId = this.RoadieUser.roadieId, - // userName = this.RoadieUser.username, - // releaseId = track.releasemedia.release.roadieId, - // trackId = track.roadieId, - // IsLocked = (track.isLocked ?? false) || (track.releasemedia.release.isLocked ?? false) || ((trackArtist ?? releaseArtist).isLocked ?? false), - // createdDateTime = track.createdDate, - // lastUpdatedDateTime = track.lastUpdated, - // releasePlayUrl = this.Request.Url.BasePath + "/play/release/" + this.Base64BearerToken + "/" + track.releasemedia.release.roadieId, - // rating = track.rating, - // userRating = userTrack.rating, - // releaseArtistId = releaseArtist.roadieId, - // releaseArtistName = releaseArtist.name, - // roadieId = track.roadieId, - // status = track.status.ToString(), - // title = track.title, - // trackArtistId = trackArtist == null ? null : trackArtist.roadieId, - // trackArtistName = trackArtist == null ? null : trackArtist.name, - // trackPlayUrl = this.Request.Url.BasePath + "/play/track/" + this.Base64BearerToken + "/" + track.roadieId, - // artistThumbnailUrl = this.Request.Url.BasePath + "/api/v1/image/artist/thumbnail/" + (trackArtist != null ? trackArtist.roadieId : releaseArtist.roadieId), - // releaseThumbnailUrl = this.Request.Url.BasePath + "/api/v1/image/release/thumbnail/" + track.releasemedia.release.roadieId, - // userThumbnailUrl = this.Request.Url.BasePath + "/api/v1/image/user/thumbnail/" + this.RoadieUser.roadieId - // }); - // } - // catch (Exception ex) - // { - // this.LoggingService.Error(ex.Serialize()); - // } - //} + if (!roadieUser.IsPrivate) + { + try + { + await this.PlayActivityHub.Clients.All.SendAsync(JsonConvert.SerializeObject(pl)); + } + catch (Exception ex) + { + this.Logger.LogError(ex); + } + } await this.DbContext.SaveChangesAsync(); sw.Stop(); - return new OperationResult + return new OperationResult { - Data = userTrack.Adapt(), + Data = pl, IsSuccess = userTrack != null, OperationTime = sw.ElapsedMilliseconds }; diff --git a/RoadieApi/Startup.cs b/RoadieApi/Startup.cs index bfcab1f..4c1c3f7 100644 --- a/RoadieApi/Startup.cs +++ b/RoadieApi/Startup.cs @@ -14,6 +14,7 @@ using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Tokens; using Microsoft.OData.Edm; using Newtonsoft.Json; +using Roadie.Api.Hubs; using Roadie.Api.Services; using Roadie.Library.Caching; using Roadie.Library.Configuration; @@ -72,6 +73,10 @@ namespace Roadie.Api // c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyComics API v1"); // c.RoutePrefix = string.Empty; //}); + app.UseSignalR(routes => + { + routes.MapHub("playActivityHub"); + }); app.UseMvc(b => { b.Select().Expand().Filter().OrderBy().MaxTop(100).Count(); @@ -176,6 +181,8 @@ namespace Roadie.Api services.AddOData(); + services.AddSignalR(); + services.AddMvc() .AddJsonOptions(options => { diff --git a/RoadieLibrary/Models/PlayActivityList.cs b/RoadieLibrary/Models/PlayActivityList.cs index b338ca8..20fb154 100644 --- a/RoadieLibrary/Models/PlayActivityList.cs +++ b/RoadieLibrary/Models/PlayActivityList.cs @@ -32,5 +32,10 @@ namespace Roadie.Library.Models public int? UserRating { get; set; } public Image UserThumbnail { get; set; } public UserTrack UserTrack { get; set; } + + public override string ToString() + { + return $"User [{ this.User }], Artist [{ this.Artist }], Release [{ this.Release }], Track [{ this.Track}]"; + } } } \ No newline at end of file