Beispiel #1
0
        public void MemberJoin(RoomMember member)
        {
            if (_members.Any(x => x.UserName == member.UserName))
            {
                return;
            }

            _members.Add(member);
            OnRoomMembersChanged?.Invoke(this, member.UserName);

            _roomEvents.Add(new UserEvent(member.UserName, member.FriendlyName, UserEventType.JoinedRoom));
            OnRoomNotification?.Invoke(this, new RoomNotification
            {
                Category = RoomNotificationCategory.Information,
                Message  = $"{member.FriendlyName} joined room"
            });

            ToggleDj(member, false);

            if (_currentTrack != null)
            {
                StartSongForMemberUgly(member);
            }

            _timeSinceEmpty = CustomFutureDateTimeOffset;
        }
Beispiel #2
0
        public void MemberJoin(RoomMember member)
        {
            if (_members.Any(x => x.UserName == member.UserName))
            {
                return;
            }

            _statisticsService.IncrementUserCount();

            _members.Add(member);
            OnRoomMembersChanged?.Invoke(this, member.UserName);

            _roomEvents.Add(new UserEvent(member.UserName, member.FriendlyName, UserEventType.JoinedRoom));
            OnRoomNotification?.Invoke(this, new RoomNotification
            {
                Category = RoomNotificationCategory.Information,
                Message  = $"{member.FriendlyName} joined room"
            });

            ToggleDj(member, false);

            if (_currentTrack != null)
            {
                StartSongForMemberUgly(member);
            }
        }
Beispiel #3
0
        public void MemberLeave(RoomMember member)
        {
            var didRemove = _members.Remove(member);

            if (!didRemove)
            {
                return;
            }

            _roomEvents.Add(new UserEvent(member.UserName, member.FriendlyName, UserEventType.LeftRoom));
            OnRoomNotification?.Invoke(this, new RoomNotification
            {
                Category = RoomNotificationCategory.Information,
                Message  = $"{member.FriendlyName} left the room"
            });

            OnRoomMembersChanged?.Invoke(this, member.UserName);

            UpdateReactionTotals();

            // this was the last member to leave
            if (!_members.Any())
            {
                _timeSinceEmpty = DateTimeOffset.Now;
            }
        }
Beispiel #4
0
        public void ToggleDj(RoomMember member, bool isDj)
        {
            member.IsDj = isDj;

            member.DjOrderNumber = isDj ? _members.Where(x => x.IsDj).Max(y => y.DjOrderNumber) + 1 : -1;

            _roomEvents.Add(new UserEvent(member.UserName, member.FriendlyName, isDj ? UserEventType.BecameDj : UserEventType.BecameListener));

            OnRoomMembersChanged?.Invoke(this, null);
        }
Beispiel #5
0
        public void ToggleDj(RoomMember member, bool isDj)
        {
            member.IsDj = isDj;

            member.DjOrderNumber = isDj ? _members.Where(x => x.IsDj).Max(y => y.DjOrderNumber) + 1 : -1;

            _roomEvents.Add(new UserEvent(member.UserName, member.FriendlyName, isDj ? UserEventType.BecameDj : UserEventType.BecameListener));
            OnRoomNotification?.Invoke(this, new RoomNotification
            {
                Category = RoomNotificationCategory.Information,
                Message  = $"{member.FriendlyName} became a {(isDj ? "DJ" : "listener")}"
            });

            OnRoomMembersChanged?.Invoke(this, null);
        }
Beispiel #6
0
        public void MemberLeave(RoomMember member)
        {
            var didRemove = _members.Remove(member);

            if (!didRemove)
            {
                return;
            }

            _roomEvents.Add(new UserEvent(member.UserName, member.FriendlyName, UserEventType.LeftRoom));

            OnRoomMembersChanged?.Invoke(this, member.UserName);

            // this was the last member to leave
            if (!_members.Any())
            {
                _timeSinceEmpty = DateTimeOffset.Now;
            }
        }
Beispiel #7
0
        public void MemberLeave(RoomMember member)
        {
            var didRemove = _members.Remove(member);

            if (!didRemove)
            {
                return;
            }

            _statisticsService.DecrementUserCount();

            _roomEvents.Add(new UserEvent(member.UserName, member.FriendlyName, UserEventType.LeftRoom));
            OnRoomNotification?.Invoke(this, new RoomNotification
            {
                Category = RoomNotificationCategory.Information,
                Message  = $"{member.FriendlyName} left the room"
            });

            OnRoomMembersChanged?.Invoke(this, member.UserName);

            UpdateReactionTotals();
        }
Beispiel #8
0
        public async Task <RoomState> TryPlayNext(bool force = false)
        {
            while (true)
            {
                // return if song is playing right now, except when we're skipping a song
                if (!force && DateTimeOffset.Now < _handledUntil)
                {
                    // we don't change room state here
                    return(new RoomState());
                }

                _currentTrack = null;

                // try getting next player
                var nextPlayer = GetNextPlayer();

                // if we don't find any we don't have a DJ - this will exit the recursion if we run out of DJs
                if (nextPlayer == null)
                {
                    CurrentRoomState = new RoomState();
                    return(CurrentRoomState);
                }

                var song = await GetSongFromQueue(nextPlayer, nextPlayer.PlaylistId);

                // success
                if (song != null)
                {
                    _currentDjNumber = nextPlayer.DjOrderNumber;

                    // start songs for everyone
                    foreach (var roomMember in _members)
                    {
                        await PlaySong(roomMember, song);
                    }

                    // set handled
                    _handledUntil = DateTimeOffset.Now.AddMilliseconds(song.DurationMs);
                    _currentTrack = song;

                    // return state
                    CurrentRoomState = new RoomState
                    {
                        IsPlayingSong               = true,
                        CurrentDjUsername           = nextPlayer.UserName,
                        CurrentDjName               = nextPlayer.FriendlyName,
                        CurrentSongArtist           = string.Join(", ", song.Artists.Select(x => x.Name).ToArray()),
                        CurrentSongTitle            = song.Name,
                        CurrentSongArtUrl           = song?.Album.Images.FirstOrDefault()?.Url ?? "/images/missingart.jpg",
                        SongStartedAtUnixTimestamp  = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
                        SongFinishesAtUnixTimestamp = _handledUntil.ToUnixTimeMilliseconds()
                    };

                    _roomEvents.Add(new SongPlayedEvent(nextPlayer.UserName, nextPlayer.FriendlyName,
                                                        $"{CurrentRoomState.CurrentSongArtist} - {CurrentRoomState.CurrentSongTitle}", song.Id, song.Uri));

                    return(CurrentRoomState);
                }

                // remove user as DJ if song is null
                nextPlayer.IsDj = false;
                OnRoomMembersChanged?.Invoke(this, null);

                // then try again
            }
        }
Beispiel #9
0
        public async Task <RoomState> TryPlayNext(bool force = false)
        {
            while (true)
            {
                // return if song is playing right now, except when we're skipping a song
                if (!force && DateTimeOffset.Now < _handledUntil)
                {
                    // we don't change room state here
                    return(new RoomState());
                }

                _currentTrack = null;

                // try getting next player
                var nextPlayer = GetNextPlayer();

                // if we don't find any we don't have a DJ - this will exit the recursion if we run out of DJs
                if (nextPlayer == null)
                {
                    CurrentRoomState = new RoomState();
                    return(CurrentRoomState);
                }

                var song = await GetSongFromQueue(nextPlayer, nextPlayer.PlaylistId);

                // success
                if (song != null)
                {
                    _currentDjNumber = nextPlayer.DjOrderNumber;

                    // do the loop on a tmp list of members, so if someone joins mid-play we don't err out
                    var tmpMembers = _members.ToList();

                    // start songs for everyone (OLD)
                    //foreach (var roomMember in tmpMembers)
                    //{
                    //    await PlaySong(roomMember, song);
                    //}

                    // start songs for everyone (NEW)
                    var sw = new Stopwatch();
                    sw.Start();
                    var playTasks = tmpMembers.Select(x => PlaySong(x, song)).ToList();
                    await Task.WhenAll(playTasks);

                    sw.Stop();
                    _logger.Log(LogLevel.Information, "Took {TimedApiPlayForAll} to start songs for {MemberCount} room members", sw.Elapsed, tmpMembers.Count);

                    // set handled
                    _handledUntil = DateTimeOffset.Now.AddMilliseconds(song.DurationMs);
                    _currentTrack = song;

                    // return state
                    CurrentRoomState = new RoomState
                    {
                        IsPlayingSong               = true,
                        CurrentDjUsername           = nextPlayer.UserName,
                        CurrentDjName               = nextPlayer.FriendlyName,
                        CurrentSongArtist           = string.Join(", ", song.Artists.Select(x => x.Name).ToArray()),
                        CurrentSongTitle            = song.Name,
                        CurrentSongArtUrl           = song?.Album.Images.FirstOrDefault()?.Url ?? "/images/missingart.jpg",
                        SongStartedAtUnixTimestamp  = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
                        SongFinishesAtUnixTimestamp = _handledUntil.ToUnixTimeMilliseconds()
                    };

                    _roomEvents.Add(new SongPlayedEvent(nextPlayer.UserName, nextPlayer.FriendlyName,
                                                        $"{CurrentRoomState.CurrentSongArtist} - {CurrentRoomState.CurrentSongTitle}", song.Id, song.Uri));

                    return(CurrentRoomState);
                }

                // remove user as DJ if song is null
                nextPlayer.IsDj = false;
                OnRoomMembersChanged?.Invoke(this, null);

                // then try again
            }
        }
Beispiel #10
0
        public async Task <RoomState> TryPlayNext(bool force = false)
        {
            while (true)
            {
                // return if song is playing right now, except when we're skipping a song
                if (!force && DateTimeOffset.Now < _handledUntil)
                {
                    // we don't change room state here
                    return(new RoomState());
                }

                // award points based on the track if there are multiple users in the room
                if (_currentTrack != null && _members.Count > 1)
                {
                    // 0 points base if song got skipped, 1 if not
                    var score = CurrentRoomState.SongFinishesAtUnixTimestamp > DateTimeOffset.Now.ToUnixTimeMilliseconds() ? 0 : 1;
                    // then 1 point for every reaction
                    foreach (var roomMember in _members)
                    {
                        // could write something for this, but eh...
                        if (roomMember.ReactionFlagsForCurrentTrack.HasFlag(Reaction.Heart))
                        {
                            score += 1;
                        }
                        if (roomMember.ReactionFlagsForCurrentTrack.HasFlag(Reaction.Rock))
                        {
                            score += 1;
                        }
                        if (roomMember.ReactionFlagsForCurrentTrack.HasFlag(Reaction.Flame))
                        {
                            score += 1;
                        }
                        if (roomMember.ReactionFlagsForCurrentTrack.HasFlag(Reaction.Clap))
                        {
                            score += 1;
                        }
                    }

                    // update score if needed
                    if (score > 0)
                    {
                        await _userScoreService.IncreaseScoreForUser(CurrentRoomState.CurrentDjUsername, score);

                        // update values as we have new scores
                        OnRoomMembersChanged?.Invoke(this, null);
                    }
                }

                _currentTrack = null;

                // try getting next player
                var nextPlayer = GetNextPlayer();

                // if we don't find any we don't have a DJ - this will exit the recursion if we run out of DJs
                if (nextPlayer == null)
                {
                    CurrentRoomState = new RoomState();
                    return(CurrentRoomState);
                }

                var song = await GetSongFromQueue(nextPlayer, nextPlayer.PlaylistId);

                // success
                if (song != null)
                {
                    _currentDjNumber = nextPlayer.DjOrderNumber;

                    // do the loop on a tmp list of members, so if someone joins mid-play we don't err out
                    var tmpMembers = _members.ToList();

                    // start songs for everyone (NEW)
                    var sw = new Stopwatch();
                    sw.Start();
                    var playTasks = tmpMembers.Select(x => PlaySong(x, song)).ToList();
                    await Task.WhenAll(playTasks);

                    sw.Stop();
                    _logger.Log(LogLevel.Information, "Took {TimedApiPlayForAll} to start songs for {MemberCount} room members", sw.Elapsed, tmpMembers.Count);

                    // set handled
                    _handledUntil = DateTimeOffset.Now.AddMilliseconds(song.DurationMs);
                    _currentTrack = song;

                    // clear reactions & update them
                    foreach (var roomMember in tmpMembers)
                    {
                        roomMember.ReactionFlagsForCurrentTrack = Reaction.None;
                    }
                    UpdateReactionTotals();

                    var artistSum = string.Join(", ", song.Artists.Select(x => x.Name).ToArray());

                    // return state
                    CurrentRoomState = new RoomState
                    {
                        IsPlayingSong               = true,
                        CurrentDjUsername           = nextPlayer.UserName,
                        CurrentDjName               = nextPlayer.FriendlyName,
                        CurrentSongArtist           = artistSum.Length > 50 ? artistSum.Substring(0, 50) + "..." : artistSum,
                        CurrentSongTitle            = song.Name.Length > 50 ? song.Name.Substring(0, 50) + "..." : song.Name,
                        CurrentSongArtUrl           = song?.Album.Images.FirstOrDefault()?.Url ?? "/images/missingart.jpg",
                        SongStartedAtUnixTimestamp  = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
                        SongFinishesAtUnixTimestamp = _handledUntil.ToUnixTimeMilliseconds()
                    };

                    _roomEvents.Add(new SongPlayedEvent(nextPlayer.UserName, nextPlayer.FriendlyName,
                                                        $"{CurrentRoomState.CurrentSongArtist} - {CurrentRoomState.CurrentSongTitle}", song.Id, song.Uri));

                    // successfully played song, so change last song played
                    _timeSinceLastSongPlayed = _handledUntil;

                    return(CurrentRoomState);
                }

                // remove user as DJ if song is null
                nextPlayer.IsDj = false;
                OnRoomMembersChanged?.Invoke(this, null);

                // then try again
            }
        }