Пример #1
0
        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>());
        }
Пример #2
0
        public async Task <OperationResult <bool> > ScanCollection(ApplicationUser user, Guid collectionId,
                                                                   bool isReadOnly = false, bool doPurgeFirst = false, bool doUpdateRanks = true)
        {
            var sw = new Stopwatch();

            sw.Start();

            var releaseIdsInCollection = new List <int>();
            var updatedReleaseIds      = new List <int>();
            var result     = new List <data.PositionArtistRelease>();
            var errors     = new List <Exception>();
            var collection = DbContext.Collections.FirstOrDefault(x => x.RoadieId == collectionId);

            if (collection == null)
            {
                await LogAndPublish($"ScanCollection Unknown Collection [{collectionId}]", LogLevel.Warning);

                return(new OperationResult <bool>(true, $"Collection Not Found [{collectionId}]"));
            }

            try
            {
                if (doPurgeFirst)
                {
                    await LogAndPublish($"ScanCollection Purgeing Collection [{collectionId}]", LogLevel.Warning);

                    var crs = DbContext.CollectionReleases.Where(x => x.CollectionId == collection.Id).ToArray();
                    DbContext.CollectionReleases.RemoveRange(crs);
                    await DbContext.SaveChangesAsync();
                }

                var collectionMissingRecords = DbContext.CollectionMissings.Where(x => x.CollectionId == collection.Id);
                DbContext.CollectionMissings.RemoveRange(collectionMissingRecords);
                await DbContext.SaveChangesAsync();

                var par = collection.PositionArtistReleases();
                if (par != null)
                {
                    var now = DateTime.UtcNow;
                    foreach (var csvRelease in par)
                    {
                        data.Artist  artist  = null;
                        data.Release release = null;

                        var searchName        = csvRelease.Artist.NormalizeName();
                        var specialSearchName = csvRelease.Artist.ToAlphanumericName();

                        var artistResults = (from a in DbContext.Artists
                                             where a.Name.Contains(searchName) ||
                                             a.SortName.Contains(searchName) ||
                                             a.AlternateNames.Contains(searchName) ||
                                             a.AlternateNames.Contains(specialSearchName)
                                             select a).ToArray();
                        if (!artistResults.Any())
                        {
                            await LogAndPublish(
                                $"Unable To Find Artist [{csvRelease.Artist}], SearchName [{searchName}]",
                                LogLevel.Warning);

                            csvRelease.Status = Statuses.Missing;
                            DbContext.CollectionMissings.Add(new data.CollectionMissing
                            {
                                CollectionId = collection.Id,
                                Position     = csvRelease.Position,
                                Artist       = searchName,
                                Release      = csvRelease.Release.NormalizeName()
                            });
                            continue;
                        }

                        foreach (var artistResult in artistResults)
                        {
                            artist            = artistResult;
                            searchName        = csvRelease.Release.NormalizeName().ToLower();
                            specialSearchName = csvRelease.Release.ToAlphanumericName();
                            release           = (from r in DbContext.Releases
                                                 where r.ArtistId == artist.Id
                                                 where r.Title.Contains(searchName) ||
                                                 r.AlternateNames.Contains(searchName) ||
                                                 r.AlternateNames.Contains(specialSearchName)
                                                 select r
                                                 ).FirstOrDefault();
                            if (release != null)
                            {
                                break;
                            }
                        }

                        if (release == null)
                        {
                            await LogAndPublish(
                                $"Unable To Find Release [{csvRelease.Release}] for Artist [{csvRelease.Artist}], SearchName [{searchName}]",
                                LogLevel.Warning);

                            csvRelease.Status = Statuses.Missing;
                            DbContext.CollectionMissings.Add(new data.CollectionMissing
                            {
                                CollectionId  = collection.Id,
                                IsArtistFound = true,
                                Position      = csvRelease.Position,
                                Artist        = csvRelease.Artist,
                                Release       = searchName
                            });
                            continue;
                        }

                        var isInCollection = DbContext.CollectionReleases.FirstOrDefault(x =>
                                                                                         x.CollectionId == collection.Id &&
                                                                                         x.ListNumber == csvRelease.Position &&
                                                                                         x.ReleaseId == release.Id);
                        var updated = false;
                        // Found in Database but not in collection add to Collection
                        if (isInCollection == null)
                        {
                            DbContext.CollectionReleases.Add(new data.CollectionRelease
                            {
                                CollectionId = collection.Id,
                                ReleaseId    = release.Id,
                                ListNumber   = csvRelease.Position
                            });
                            updated = true;
                        }
                        // If Item in Collection is at different List number update CollectionRelease
                        else if (isInCollection.ListNumber != csvRelease.Position)
                        {
                            isInCollection.LastUpdated = now;
                            isInCollection.ListNumber  = csvRelease.Position;
                            updated = true;
                        }

                        if (updated && !updatedReleaseIds.Any(x => x == release.Id))
                        {
                            updatedReleaseIds.Add(release.Id);
                        }
                        releaseIdsInCollection.Add(release.Id);
                    }

                    collection.LastUpdated = now;
                    await DbContext.SaveChangesAsync();

                    var dto = new CollectionList
                    {
                        CollectionCount      = collection.CollectionCount,
                        CollectionFoundCount = (from cr in DbContext.CollectionReleases
                                                where cr.CollectionId == collection.Id
                                                select cr.CollectionId).Count()
                    };
                    if (dto.PercentComplete == 100)
                    {
                        // Lock so future implicit scans dont happen, with DB RI when releases are deleted they are removed from collection
                        collection.IsLocked = true;
                        collection.Status   = Statuses.Complete;
                    }
                    else
                    {
                        collection.Status = Statuses.Incomplete;
                    }

                    var collectionReleasesToRemove = (from cr in DbContext.CollectionReleases
                                                      where cr.CollectionId == collection.Id
                                                      where !releaseIdsInCollection.Contains(cr.ReleaseId)
                                                      select cr).ToArray();
                    if (collectionReleasesToRemove.Any())
                    {
                        await LogAndPublish(
                            $"Removing [{collectionReleasesToRemove.Count()}] Stale Release Records from Collection.",
                            LogLevel.Information);

                        DbContext.CollectionReleases.RemoveRange(collectionReleasesToRemove);
                    }

                    await DbContext.SaveChangesAsync();

                    if (doUpdateRanks)
                    {
                        foreach (var updatedReleaseId in updatedReleaseIds)
                        {
                            await UpdateReleaseRank(updatedReleaseId);
                        }
                    }
                    CacheManager.ClearRegion(collection.CacheRegion);
                }
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                errors.Add(ex);
            }

            sw.Stop();
            Logger.LogInformation(string.Format("RescanCollection `{0}`, By User `{1}`, ElapsedTime [{2}]", collection,
                                                user, sw.ElapsedMilliseconds));

            return(new OperationResult <bool>
            {
                AdditionalData = new Dictionary <string, object> {
                    { "updatedReleaseIds", updatedReleaseIds.ToArray() }
                },
                IsSuccess = !errors.Any(),
                Data = true,
                OperationTime = sw.ElapsedMilliseconds,
                Errors = errors
            });
        }
Пример #3
0
        /// <summary>
        /// The user has played a track.
        /// </summary>
        public override async Task <OperationResult <bool> > Scrobble(User roadieUser, ScrobbleInfo scrobble)
        {
            try
            {
                // If less than half of duration then do nothing
                if (scrobble.ElapsedTimeOfTrackPlayed.TotalSeconds < (scrobble.TrackDuration.TotalSeconds / 2))
                {
                    return(new OperationResult <bool>
                    {
                        Data = true,
                        IsSuccess = true
                    });
                }

                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 == scrobble.TrackId);
                if (track == null)
                {
                    return(new OperationResult <bool>($"Scrobble: Unable To Find Track [{ scrobble.TrackId }]"));
                }
                if (!track.IsValid)
                {
                    return(new OperationResult <bool>($"Scrobble: Invalid Track. Track Id [{scrobble.TrackId}], FilePath [{track.FilePath}], Filename [{track.FileName}]"));
                }
                data.UserTrack userTrack = null;
                var            now       = DateTime.UtcNow;
                var            success   = false;
                try
                {
                    var user = this.DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId);
                    userTrack = this.DbContext.UserTracks.FirstOrDefault(x => x.UserId == roadieUser.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;

                    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);
                    }

                    await this.DbContext.SaveChangesAsync();

                    this.CacheManager.ClearRegion(track.CacheRegion);
                    this.CacheManager.ClearRegion(track.ReleaseMedia.Release.CacheRegion);
                    this.CacheManager.ClearRegion(track.ReleaseMedia.Release.Artist.CacheRegion);
                    this.CacheManager.ClearRegion(user.CacheRegion);

                    success = true;
                }
                catch (Exception ex)
                {
                    this.Logger.LogError(ex, $"Error in Scrobble, Creating UserTrack: User `{ roadieUser}` TrackId [{ track.Id }");
                }
                sw.Stop();
                this.Logger.LogInformation($"RoadieScrobbler: RoadieUser `{ roadieUser }` Scrobble `{ scrobble }`");
                return(new OperationResult <bool>
                {
                    Data = success,
                    IsSuccess = userTrack != null,
                    OperationTime = sw.ElapsedMilliseconds
                });
            }
            catch (Exception ex)
            {
                this.Logger.LogError(ex, $"Scrobble RoadieUser `{ roadieUser }` Scrobble `{ scrobble }`");
            }
            return(new OperationResult <bool>());
        }