public async Task <OperationResult <PlayActivityList> > CreatePlayActivity(User roadieUser, TrackStreamInfo streamInfo) { try { var sw = Stopwatch.StartNew(); var track = this.DbContext.Tracks .Include(x => x.ReleaseMedia) .Include(x => x.ReleaseMedia.Release) .Include(x => x.ReleaseMedia.Release.Artist) .Include(x => x.TrackArtist) .FirstOrDefault(x => x.RoadieId == SafeParser.ToGuid(streamInfo.Track.Value)); if (track == null) { return(new OperationResult <PlayActivityList>($"CreatePlayActivity: Unable To Find Track [{ streamInfo.Track.Value }]")); } if (!track.IsValid) { return(new OperationResult <PlayActivityList>($"CreatePlayActivity: Invalid Track. Track Id [{streamInfo.Track.Value}], FilePath [{track.FilePath}], Filename [{track.FileName}]")); } data.UserTrack userTrack = null; var now = DateTime.UtcNow; try { var user = roadieUser != null?this.DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId) : null; if (user != null) { userTrack = this.DbContext.UserTracks.FirstOrDefault(x => x.UserId == user.Id && x.TrackId == track.Id); if (userTrack == null) { userTrack = new data.UserTrack(now) { UserId = user.Id, TrackId = track.Id }; this.DbContext.UserTracks.Add(userTrack); } userTrack.LastPlayed = now; userTrack.PlayedCount = (userTrack.PlayedCount ?? 0) + 1; this.CacheManager.ClearRegion(user.CacheRegion); await this.DbContext.SaveChangesAsync(); } } catch (Exception ex) { this.Logger.LogError(ex, $"Error in CreatePlayActivity, Creating UserTrack: User `{ roadieUser}` TrackId [{ track.Id }"); } track.PlayedCount = (track.PlayedCount ?? 0) + 1; track.LastPlayed = now; var release = this.DbContext.Releases.Include(x => x.Artist).FirstOrDefault(x => x.RoadieId == track.ReleaseMedia.Release.RoadieId); release.LastPlayed = now; release.PlayedCount = (release.PlayedCount ?? 0) + 1; var artist = this.DbContext.Artists.FirstOrDefault(x => x.RoadieId == release.Artist.RoadieId); artist.LastPlayed = now; artist.PlayedCount = (artist.PlayedCount ?? 0) + 1; data.Artist trackArtist = null; if (track.ArtistId.HasValue) { trackArtist = this.DbContext.Artists.FirstOrDefault(x => x.Id == track.ArtistId); trackArtist.LastPlayed = now; trackArtist.PlayedCount = (trackArtist.PlayedCount ?? 0) + 1; this.CacheManager.ClearRegion(trackArtist.CacheRegion); } this.CacheManager.ClearRegion(track.CacheRegion); this.CacheManager.ClearRegion(track.ReleaseMedia.Release.CacheRegion); this.CacheManager.ClearRegion(track.ReleaseMedia.Release.Artist.CacheRegion); 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}.mp3", 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 (!roadieUser.IsPrivate) { try { await this.PlayActivityHub.Clients.All.SendAsync("SendActivity", pl); } catch (Exception ex) { this.Logger.LogError(ex); } } await this.DbContext.SaveChangesAsync(); sw.Stop(); return(new OperationResult <PlayActivityList> { Data = pl, IsSuccess = userTrack != null, OperationTime = sw.ElapsedMilliseconds }); } catch (Exception ex) { this.Logger.LogError(ex, $"CreatePlayActivity RoadieUser `{ roadieUser }` StreamInfo `{ streamInfo }`"); } return(new OperationResult <PlayActivityList>()); }
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 }); }