Example #1
0
        public async Task <IActionResult> LeaveRoom(RoomModel model)
        {
            var username = HttpContext.User.Claims.GetSpotifyUsername();

            var hasRoom = _roomService.TryGetRoomForUsername(model.UserName, out var room);

            if (username == model.UserName && hasRoom)
            {
                room.MemberLeave(room.Members.FirstOrDefault(x => x.UserName == username));

                _devicePersistenceService.CleanDeviceState(username);
            }

            return(RedirectToAction(nameof(Index)));
        }
Example #2
0
        private async Task PlaySong(RoomMember member, FullTrack song, int positionMs = 0, bool canRetry = true)
        {
            try
            {
                var api = await _spotifyAccessService.TryGetMemberApi(member.UserName);

                var devices = await api.GetDevicesAsync();

                devices.ThrowOnError(nameof(api.GetDevices));

                if (!devices.Devices.Any())
                {
                    throw new Exception("No devices available to play on!");
                }

                var activeDevice = devices.Devices.FirstOrDefault(x => x.IsActive);

                var hasShouldBeActive = _devicePersistenceService.TryGetActiveDeviceId(member.UserName, out var shouldBeActiveDeviceId);

                if (activeDevice != null && activeDevice.Id != shouldBeActiveDeviceId)
                {
                    // set if changed
                    _devicePersistenceService.SetDeviceState(member.UserName, activeDevice.Id);
                }

                // active device was somehow lost, if it's still in the list then reactivate it
                if (activeDevice == null && hasShouldBeActive)
                {
                    activeDevice = devices.Devices.FirstOrDefault(x => x.Id == shouldBeActiveDeviceId);
                }

                if (activeDevice == null)
                {
                    _devicePersistenceService.CleanDeviceState(member.UserName);
                    throw new Exception("No active device found to play music on.");
                }

                var resume = await api.ResumePlaybackAsync(deviceId : activeDevice.Id, uris : new List <string> {
                    song.Uri
                }, offset : 0, positionMs : positionMs);

                resume.ThrowOnError(nameof(api.ResumePlaybackAsync));

                // reset failure count if playback started successfully
                if (member.PlayFailureCount > 0)
                {
                    member.PlayFailureCount = 0;

                    _logger.Log(LogLevel.Information, "Reset play failure count for {Username}", member.UserName);
                }
            }
            catch (Exception e)
            {
                _logger.Log(LogLevel.Warning, "Failed to play song for {Username} because {@Exception}", member.UserName, e);
                OnRoomNotification?.Invoke(this, new RoomNotification
                {
                    Category = RoomNotificationCategory.Error,
                    Message  = $"Failed to play song",
                    TargetId = member.ConnectionId
                });

                if (e.Message.Contains("HTTP 5") && canRetry)
                {
                    // if it's a server side error let's add it to the retry queue
                    async Task RetryTask()
                    {
                        // make sure user hasn't left in the last room-cycle
                        if (!_members.Contains(member))
                        {
                            return;
                        }
                        // try starting song again
                        var left = _handledUntil.ToUnixTimeMilliseconds() - DateTimeOffset.Now.ToUnixTimeMilliseconds();

                        await PlaySong(member, _currentTrack, (int)(_currentTrack.DurationMs - left), false);
                    }

                    _logger.Log(LogLevel.Information, "Added retry task for {UserName}", member.UserName);

                    _roomRetries.Add(RetryTask);
                }
                else
                {
                    // not a server side error, increment member failure count
                    member.PlayFailureCount += 1;

                    _logger.Log(LogLevel.Information, "Incremented play failure count to {PlayFailureCount} for {Username}", member.PlayFailureCount, member.UserName);
                }

                Debug.WriteLine(e);
            }
        }