private void NotifyIfLive(LivestreamModel livestreamModel)
        {
            if (!hasRefreshed)
            {
                return;                // dont show notifications for the initial refresh
            }
            if (!livestreamModel.Live)
            {
                return;                        // only care about streams coming online
            }
            // avoid a twitch api bug where sometimes online streams will not be returned when querying for online streams
            // the best way we can work around this is to pick a reasonable uptime value after which we will never show online notifications.
            // we check the LastLiveTime for null to ensure we will always notify the first time a stream come online
            if (livestreamModel.LastLiveTime != null && livestreamModel.Uptime > TimeSpan.FromMinutes(5))
            {
                return;
            }

            var notification = new LivestreamNotification()
            {
                Title           = $"{livestreamModel.DisplayName} Online",
                Message         = livestreamModel.Description,
                ImageUrl        = livestreamModel.ThumbnailUrls?.Small,
                LivestreamModel = livestreamModel,
            };

            AddNotification(notification);
        }
Ejemplo n.º 2
0
        public static LivestreamModel PopulateWithStreamDetails(
            this LivestreamModel livestreamModel,
            Stream streamDetails)
        {
            if (streamDetails == null)
            {
                return(livestreamModel);
            }

            livestreamModel.Viewers       = streamDetails.Viewers ?? 0;
            livestreamModel.ThumbnailUrls = new ThumbnailUrls()
            {
                Large  = streamDetails.Preview.Large,
                Medium = streamDetails.Preview.Medium,
                Small  = streamDetails.Preview.Small,
            };
            if (streamDetails.CreatedAt != null)
            {
                livestreamModel.StartTime = DateTimeOffset.Parse(streamDetails.CreatedAt);
                livestreamModel.NotifyOfPropertyChange(nameof(livestreamModel.Uptime));
            }

            // need to update other details before flipping the stream to online
            livestreamModel.Live = streamDetails.Viewers.HasValue;

            if (streamDetails.Channel != null)
            {
                livestreamModel.PopulateWithChannel(streamDetails.Channel);
            }

            return(livestreamModel);
        }
Ejemplo n.º 3
0
        public static LivestreamModel PopulateWithStreamDetails(
            this LivestreamModel livestreamModel,
            Stream stream)
        {
            if (stream == null)
            {
                return(livestreamModel);
            }

            livestreamModel.Viewers = stream.ViewerCount;
            // the values here are what the v5 api returned for large/medium/small
            var largeThumbnail  = stream.ThumbnailTemplateUrl.Replace("{width}", "640").Replace("{height}", "360");
            var mediumThumbnail = stream.ThumbnailTemplateUrl.Replace("{width}", "320").Replace("{height}", "180");
            var smallThumbnail  = stream.ThumbnailTemplateUrl.Replace("{width}", "80").Replace("{height}", "45");

            livestreamModel.ThumbnailUrls = new ThumbnailUrls()
            {
                Large  = largeThumbnail,
                Medium = mediumThumbnail,
                Small  = smallThumbnail,
            };
            livestreamModel.StartTime = stream.StartedAt;

            // need to update other details before flipping the stream to online
            livestreamModel.Live = stream.Type == "live";

            livestreamModel.DisplayName = stream.UserName;
            livestreamModel.Description = stream.Title;

            return(livestreamModel);
        }
Ejemplo n.º 4
0
        public async Task OpenStream(LivestreamModel livestreamModel, string streamQuality, IViewAware viewAware)
        {
            if (livestreamModel?.ApiClient == null || !livestreamModel.Live)
            {
                return;
            }

            string livestreamerArgs = $"{livestreamModel.StreamUrl} {streamQuality}";
            var    apiClient        = livestreamModel.ApiClient;

            // hack to pass through the client id to livestreamer
            if (settingsHandler.Settings.PassthroughClientId)
            {
                if (apiClient is TwitchApiClient)
                {
                    livestreamerArgs = $"--http-header {RequestConstants.ClientIdHeaderKey}={RequestConstants.ClientIdHeaderValue} {livestreamerArgs}";
                }
            }
            else
            {
                if (!apiClient.IsAuthorized)
                {
                    await apiClient.Authorize(viewAware);
                }

                if (apiClient.IsAuthorized && !string.IsNullOrWhiteSpace(apiClient.LivestreamerAuthorizationArg))
                {
                    livestreamerArgs += " " + apiClient.LivestreamerAuthorizationArg;
                }
            }

            var launcher = Path.GetFileName(settingsHandler.Settings.LivestreamerFullPath);

            var messageBoxViewModel = ShowLivestreamerLoadMessageBox(
                title: $"Stream '{livestreamModel.DisplayName}'",
                messageText: $"Launching {settingsHandler.Settings.LivestreamExeDisplayName}....{Environment.NewLine}'{launcher} {livestreamerArgs}'");

            // Notify the user if the quality has been swapped back to source due to the livestream not being partenered (twitch specific).
            if (!livestreamModel.IsPartner && streamQuality != StreamQuality.Best.ToString())
            {
                messageBoxViewModel.MessageText += Environment.NewLine +
                                                   $"[NOTE] Channel is not a twitch partner so falling back to {StreamQuality.Best} quality";
            }

            lock (WatchingStreamsLock)
            {
                watchingStreams.Add(livestreamModel);
            }

            StartLivestreamer(livestreamerArgs, streamQuality, messageBoxViewModel, onClose: () =>
            {
                lock (WatchingStreamsLock)
                {
                    watchingStreams.Remove(livestreamModel);
                }
            });
        }
        private void HookLivestreamChangeEvents(LivestreamModel newLivestream)
        {
            if (newLivestream == null)
            {
                throw new ArgumentNullException(nameof(newLivestream));
            }

            newLivestream.PropertyChanged += LivestreamOnPropertyChanged;
        }
        private void UnhookLivestreamChangeEvents(LivestreamModel removedLivestream)
        {
            if (removedLivestream == null)
            {
                throw new ArgumentNullException(nameof(removedLivestream));
            }

            removedLivestream.PropertyChanged += LivestreamOnPropertyChanged;
        }
        public TopStreamResult()
        {
            if (!Execute.InDesignMode)
            {
                throw new InvalidOperationException("Design time only constructor");
            }

            LivestreamModel   = new LivestreamModel();
            ChannelIdentifier = new ChannelIdentifier();
        }
Ejemplo n.º 8
0
        public async Task OpenStream(LivestreamModel livestreamModel, IViewAware viewAware)
        {
            if (livestreamModel?.ApiClient == null || !livestreamModel.Live)
            {
                return;
            }

            var favoriteQualities = settingsHandler.Settings.GetStreamQualities(livestreamModel.ApiClient.ApiName);
            var qualities         = favoriteQualities.Qualities.Union(new[] { favoriteQualities.FallbackQuality });

            var    streamUrl        = await livestreamModel.GetStreamUrl;
            string livestreamerArgs = $"{streamUrl} {string.Join(",", qualities)}";
            var    apiClient        = livestreamModel.ApiClient;

            // hack to pass through the client id to livestreamer
            if (settingsHandler.Settings.PassthroughClientId)
            {
                if (apiClient is TwitchApiClient)
                {
                    livestreamerArgs = $"--http-header {RequestConstants.ClientIdHeaderKey}={RequestConstants.ClientIdHeaderValue} {livestreamerArgs}";
                }
            }
            else
            {
                if (!apiClient.IsAuthorized)
                {
                    await apiClient.Authorize(viewAware);
                }

                if (apiClient.IsAuthorized && !string.IsNullOrWhiteSpace(apiClient.LivestreamerAuthorizationArg))
                {
                    livestreamerArgs += " " + apiClient.LivestreamerAuthorizationArg;
                }
            }

            var launcher = Path.GetFileName(settingsHandler.Settings.LivestreamerFullPath);

            var messageBoxViewModel = ShowLivestreamerLoadMessageBox(
                title: $"Stream '{livestreamModel.DisplayName}'",
                messageText: $"Launching {settingsHandler.Settings.LivestreamExeDisplayName}....{Environment.NewLine}'{launcher} {livestreamerArgs}'");

            lock (WatchingStreamsLock)
            {
                watchingStreams.Add(livestreamModel);
            }

            StartLivestreamer(livestreamerArgs, messageBoxViewModel, onClose: () =>
            {
                lock (WatchingStreamsLock)
                {
                    watchingStreams.Remove(livestreamModel);
                }
            });
        }
Ejemplo n.º 9
0
        public async Task OpenChat(LivestreamModel livestreamModel, IViewAware fromScreen)
        {
            // guard against invalid/missing chrome path
            var chromeLocation = settingsHandler.Settings.ChromeFullPath;

            if (string.IsNullOrWhiteSpace(chromeLocation))
            {
                await fromScreen.ShowMessageAsync("No chrome locations specified",
                                                  $"Chrome location is not set in settings.{Environment.NewLine}Chat relies on chrome to function.");

                return;
            }
            if (!File.Exists(chromeLocation))
            {
                await fromScreen.ShowMessageAsync("Chrome not found",
                                                  $"Could not find chrome @ {chromeLocation}.{Environment.NewLine}Chat relies on chrome to function.");

                return;
            }
            // guard against stream provider not having chat support
            if (!livestreamModel.ApiClient.HasChatSupport)
            {
                await fromScreen.ShowMessageAsync("Chat not supported",
                                                  $"No external chat support for stream provider '{livestreamModel.ApiClient.ApiName}'");

                return;
            }

            string chromeArgs = $"--app={livestreamModel.ChatUrl} --window-size=350,758";

            await Task.Run(async() =>
            {
                try
                {
                    var proc = new Process
                    {
                        StartInfo =
                        {
                            FileName        = chromeLocation,
                            Arguments       = chromeArgs,
                            CreateNoWindow  = true,
                            UseShellExecute = false
                        }
                    };

                    proc.Start();
                }
                catch (Exception ex)
                {
                    await fromScreen.ShowMessageAsync("Error launching chat", ex.Message);
                }
            });
        }
 public TopStreamResult(LivestreamModel livestreamModel, ChannelIdentifier channelIdentifier)
 {
     if (livestreamModel == null)
     {
         throw new ArgumentNullException(nameof(livestreamModel));
     }
     if (channelIdentifier == null)
     {
         throw new ArgumentNullException(nameof(channelIdentifier));
     }
     LivestreamModel   = livestreamModel;
     ChannelIdentifier = channelIdentifier;
 }
Ejemplo n.º 11
0
        public static void PopulateSelf(this LivestreamModel livestreamModel, LivestreamModel consume)
        {
            livestreamModel.BroadcasterLanguage = consume.BroadcasterLanguage;
            livestreamModel.Description         = consume.Description?.Trim();
            livestreamModel.DisplayName         = consume.DisplayName;
            livestreamModel.Game          = consume.Game;
            livestreamModel.IsPartner     = consume.IsPartner;
            livestreamModel.Language      = consume.Language;
            livestreamModel.ThumbnailUrls = consume.ThumbnailUrls;

            livestreamModel.Viewers   = consume.Viewers;
            livestreamModel.StartTime = consume.StartTime;
            livestreamModel.Live      = consume.Live;
        }
Ejemplo n.º 12
0
        public static void PopulateWithChannel(this LivestreamModel livestreamModel, Channel channel)
        {
            if (channel == null)
            {
                return;
            }

            livestreamModel.DisplayName         = channel.DisplayName;
            livestreamModel.Description         = channel.Status?.Trim();
            livestreamModel.Game                = channel.Game;
            livestreamModel.IsPartner           = channel.Partner.HasValue && channel.Partner.Value;
            livestreamModel.BroadcasterLanguage = channel.BroadcasterLanguage;
            livestreamModel.Language            = channel.Language;
        }
Ejemplo n.º 13
0
 public static UniqueStreamKey ToExcludeNotify(this LivestreamModel livestreamModel)
 {
     return(new UniqueStreamKey(livestreamModel.ApiClient.ApiName, livestreamModel.Id));
 }
Ejemplo n.º 14
0
        public async Task OpenChat(LivestreamModel livestreamModel, IViewAware fromScreen)
        {
            // guard against stream provider with unknown chat support
            if (!livestreamModel.ApiClient.HasChatSupport)
            {
                await fromScreen.ShowMessageAsync("Chat not supported",
                                                  $"No external chat support for stream provider '{livestreamModel.ApiClient.ApiName}'");

                return;
            }

            if (string.IsNullOrWhiteSpace(settingsHandler.Settings.ChatCommandLine))
            {
                await fromScreen.ShowMessageAsync("No chat command specified", "Chat command is not set in settings.");

                return;
            }

            // guard against chat command that contains no url token
            if (!settingsHandler.Settings.ChatCommandLine.Contains(Settings.CHAT_URL_REPLACEMENT_TOKEN))
            {
                await fromScreen.ShowMessageAsync("Missing url token in chat command",
                                                  $"Chat command is missing the url token {Settings.CHAT_URL_REPLACEMENT_TOKEN}.");

                return;
            }

            var command = settingsHandler.Settings.ChatCommandLine.Replace(Settings.CHAT_URL_REPLACEMENT_TOKEN, livestreamModel.ChatUrl);

            await Task.Run(async() =>
            {
                try
                {
                    var proc = new Process
                    {
                        StartInfo =
                        {
                            FileName               = "cmd.exe",
                            Arguments              = "/c " + command,
                            CreateNoWindow         = true,
                            UseShellExecute        = false,
                            RedirectStandardOutput = true,
                            RedirectStandardError  = true,
                        }
                    };

                    proc.Start();
                    string errorOutput = proc.StandardError.ReadToEnd();
                    proc.WaitForExit();

                    // check for exit code as well because sometimes processes emit warnings in the error output stream
                    if (proc.ExitCode != 0 && errorOutput != string.Empty)
                    {
                        await Execute.OnUIThreadAsync(async() => await fromScreen.ShowMessageAsync("Error launching chat", errorOutput));
                    }
                }
                catch (Exception ex)
                {
                    await Execute.OnUIThreadAsync(async() => await fromScreen.ShowMessageAsync("Error launching chat", ex.Message));
                }
            });
        }
 public TopStreamResult(LivestreamModel livestreamModel, ChannelIdentifier channelIdentifier)
 {
     LivestreamModel   = livestreamModel ?? throw new ArgumentNullException(nameof(livestreamModel));
     ChannelIdentifier = channelIdentifier ?? throw new ArgumentNullException(nameof(channelIdentifier));
 }
 protected bool Equals(LivestreamModel other)
 {
     return(Equals(UniqueStreamKey, other.UniqueStreamKey));
 }