Esempio n. 1
0
        private async Task PlaySong(RoomMember member, FullTrack song, int positionMs = 0)
        {
            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 device = devices.Devices.FirstOrDefault(x => x.IsActive) ?? devices.Devices.First();

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

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

                // we don't care if this one fails
                await api.SetRepeatModeAsync(RepeatState.Off, device.Id);
            }
            catch (Exception e)
            {
                _logger.Log(LogLevel.Warning, "Failed to play song for {Username} because {@Exception}", member.UserName, e);
                // oh well
                Debug.WriteLine(e);
            }
        }
Esempio n. 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 device = devices.Devices.FirstOrDefault(x => x.IsActive) ?? devices.Devices.First();

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

                resume.ThrowOnError(nameof(api.ResumePlaybackAsync));
            }
            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 oh well

                Debug.WriteLine(e);
            }
        }
Esempio n. 3
0
        public async Task <IActionResult> Index(string join = null)
        {
            var username = HttpContext.User.Claims.GetSpotifyUsername();

            var api = await _spotifyAccessService.TryGetMemberApi(username);

            // guarantee playlist
            var profile = await api.GetPrivateProfileAsync();

            var queuePlaylist    = "";
            var queuePlaylistUrl = "";
            var playlistMessage  = "";

            var       offset          = 0;
            const int paginationLimit = 50;
            var       playlists       = await api.GetUserPlaylistsAsync(profile.Id, paginationLimit, offset);

            // ReSharper disable once UselessBinaryOperation (this seems to be a resharper issue)
            offset += paginationLimit;

            do
            {
                var playlist = playlists.Items.FirstOrDefault(x =>
                                                              !x.Collaborative && !x.Public && x.Name == Constants.QueuePlaylistName);

                // found it
                if (playlist != null)
                {
                    queuePlaylist    = playlist.Id;
                    queuePlaylistUrl = playlist.Uri;
                    playlistMessage  = "Found existing queue playlist: ";
                    break;
                }

                playlists = await api.GetUserPlaylistsAsync(profile.Id, paginationLimit, offset);

                offset += paginationLimit;
            } while (playlists.HasNextPage());

            // if we didn't find the playlist create it
            if (string.IsNullOrWhiteSpace(queuePlaylist))
            {
                var newPlaylist = await api.CreatePlaylistAsync(profile.Id, Constants.QueuePlaylistName, false, false,
                                                                "PugetSound Queue playlist - add songs here you want to play");

                queuePlaylist    = newPlaylist.Id;
                queuePlaylistUrl = newPlaylist.Uri;
                playlistMessage  = "Created queue playlist: ";

                _logger.Log(LogLevel.Information, "Created queue playlist for {Username}", username);
            }
            else
            {
                _logger.Log(LogLevel.Information, "Found queue playlist for {Username}", username);
            }

            var friendlyName = HttpContext.User.Claims.GetSpotifyFriendlyName();

            var alreadyInRoom = _roomService.TryGetRoomForUsername(username, out var prevRoom);

            // log

            _logger.Log(LogLevel.Information, "Welcoming {FriendlyName} as {Username}", friendlyName, username);

            if (alreadyInRoom)
            {
                _logger.Log(LogLevel.Information, "Pre-filled {Room} for {Username}", prevRoom.RoomId, username);
            }

            // return login page

            return(View(new IndexModel
            {
                UserName = username,
                FriendlyName = friendlyName,
                ProfileLink = profile.Uri,
                PlaylistLink = queuePlaylistUrl,
                PlaylistMessage = playlistMessage,
                PlaylistId = queuePlaylist,
                IsAlreadyInRoom = alreadyInRoom,
                RoomName = alreadyInRoom ? prevRoom.RoomId : join ?? ""
            }));
        }
Esempio n. 4
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);
            }
        }