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