Merge pull request #2 from barkermn01/SelectedStreamers

Selected streamers
This commit is contained in:
Martin Barker (Keatran)
2023-02-21 21:27:27 +00:00
committed by GitHub
24 changed files with 565 additions and 154 deletions

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TwitchDesktopNotifications.Core
{
public class Logger : SingletonFactory<Logger>, Singleton
{
private string _name;
private StreamWriter sw;
public Logger()
{
_name = DateTime.Now.ToString("dd_mm_yyyy HH_mm")+".log";
}
~Logger()
{
if (sw != null)
{
sw.Flush();
sw.Close();
}
}
public StreamWriter Writer {
get {
if(sw == null)
{
sw = new StreamWriter(_name);
}
return sw;
}
}
}
}

View File

@@ -10,12 +10,14 @@ using Windows.Foundation.Collections;
using System.Diagnostics; using System.Diagnostics;
using System.ComponentModel; using System.ComponentModel;
using Windows.UI.Notifications; using Windows.UI.Notifications;
using System.Net.Http;
namespace TwitchDesktopNotifications.Core namespace TwitchDesktopNotifications.Core
{ {
internal class Notification public class Notification : SingletonFactory<Notification>, Singleton
{ {
private Notification() { private WebClient webClient = new WebClient();
public Notification() {
ToastNotificationManagerCompat.OnActivated += toastArgs => ToastNotificationManagerCompat.OnActivated += toastArgs =>
{ {
// Obtain the arguments from the notification // Obtain the arguments from the notification
@@ -34,22 +36,16 @@ namespace TwitchDesktopNotifications.Core
myProcess.StartInfo.UseShellExecute = true; myProcess.StartInfo.UseShellExecute = true;
myProcess.StartInfo.FileName = args["streamerUrl"]; myProcess.StartInfo.FileName = args["streamerUrl"];
myProcess.Start(); myProcess.Start();
}else if( args.Contains("action") && args["action"] == "ignore")
{
NotifyManager.AddStreamerToIgnoreList(args["streamerName"]);
} }
}catch(Exception ex) { } }catch(Exception ex) {
Logger.GetInstance().Writer.WriteLine(ex.ToString());
}
}; };
} }
private static Notification Instance;
public static Notification GetInstance()
{
if(Instance == null)
{
Instance = new Notification();
}
return Instance;
}
public void sendNotification(String streamerName, String streamerUrl, String profilePic, String streamThumbnail, String title) public void sendNotification(String streamerName, String streamerUrl, String profilePic, String streamThumbnail, String title)
{ {
String FilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TwitchNotify"); String FilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TwitchNotify");
@@ -60,52 +56,64 @@ namespace TwitchDesktopNotifications.Core
string fileNameProfilePic = profilePic.Split("/").Last(); string fileNameProfilePic = profilePic.Split("/").Last();
if (!File.Exists(FilePath + "/" + fileNameProfilePic)) if (!File.Exists(FilePath + "/" + fileNameProfilePic))
{ {
(new WebClient()).DownloadFile(new Uri(profilePic), FilePath + "/" + fileNameProfilePic); webClient.DownloadFile(new Uri(profilePic), FilePath + "/" + fileNameProfilePic);
} }
// download there profile picture // download there profile picture
string fileNameThumbnailPic = streamThumbnail.Split("/").Last(); string fileNameThumbnailPic = streamThumbnail.Split("/").Last();
(new WebClient()).DownloadFile(new Uri(streamThumbnail), webClient.DownloadFile(new Uri(streamThumbnail),
FilePath + "/" + fileNameThumbnailPic FilePath + "/" + fileNameThumbnailPic
); );
var builder = new ToastContentBuilder() if (NotifyManager.ShouldNotify(streamerName))
.AddArgument("streamerUrl", streamerUrl)
.AddArgument("thumbnail_path", FilePath + "/" + fileNameThumbnailPic)
.AddText(streamerName + " is now live on Twitch")
.AddHeroImage(new Uri("file://" + (FilePath + "/" + fileNameThumbnailPic).Replace("\\", "/")))
.AddAppLogoOverride(new Uri("file://" + (FilePath + "/" + fileNameProfilePic).Replace("\\", "/")), ToastGenericAppLogoCrop.Circle)
.AddButton(new ToastButton()
.SetContent("Watch " + streamerName)
.AddArgument("action", "watch")
.SetBackgroundActivation())
.AddButton(new ToastButton()
.SetContent("Dismiss")
.AddArgument("action", "nothing")
.SetBackgroundActivation());
if(title != "") {
builder.AddText(title);
}
builder.Show(toast =>
{ {
toast.ExpirationTime = DateTime.Now.AddSeconds(15); var builder = new ToastContentBuilder()
toast.Dismissed += (ToastNotification sender, ToastDismissedEventArgs args) => .AddArgument("streamerUrl", streamerUrl)
.AddArgument("streamerName", streamerName)
.AddArgument("thumbnail_path", FilePath + "/" + fileNameThumbnailPic)
.AddText(streamerName + " is now live on Twitch")
.AddHeroImage(new Uri("file://" + (FilePath + "/" + fileNameThumbnailPic).Replace("\\", "/")))
.AddAppLogoOverride(new Uri("file://" + (FilePath + "/" + fileNameProfilePic).Replace("\\", "/")), ToastGenericAppLogoCrop.Circle)
.AddButton(new ToastButton()
.SetContent("Watch ")
.AddArgument("action", "watch")
.SetBackgroundActivation())
.AddButton(new ToastButton()
.SetContent("Dismiss")
.AddArgument("action", "nothing")
.SetBackgroundActivation())
.AddButton(new ToastButton()
.SetContent("Ignore")
.AddArgument("action", "ignore")
.SetBackgroundActivation());
if (title != "")
{ {
try builder.AddText(title);
{ }
File.Delete(FilePath + "/" + fileNameThumbnailPic); builder.Show(toast =>
}catch(Exception) { }
};
toast.Activated += (ToastNotification sender, object args) =>
{ {
try toast.ExpirationTime = DateTime.Now.AddSeconds(15);
toast.Dismissed += (ToastNotification sender, ToastDismissedEventArgs args) =>
{ {
File.Delete(FilePath + "/" + fileNameThumbnailPic); try
} {
catch (Exception) { } File.Delete(FilePath + "/" + fileNameThumbnailPic);
}; }
}); catch (Exception) { }
builder = null;
};
toast.Activated += (ToastNotification sender, object args) =>
{
try
{
File.Delete(FilePath + "/" + fileNameThumbnailPic);
}
catch (Exception) { }
builder = null;
};
});
}
} }
} }
} }

View File

@@ -0,0 +1,29 @@
using Microsoft.Toolkit.Uwp.Notifications;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using TwitchDesktopNotifications.JsonStructure.Helix;
namespace TwitchDesktopNotifications.Core
{
internal class NotifyManager
{
public static Boolean ShouldNotify(String streamerName)
{
if(DataStore.GetInstance().Store.SteamersToIgnore == null || DataStore.GetInstance().Store.SteamersToIgnore.Streamers == null) {
return true;
}
return !UIStreamer.GetCreateStreamer(streamerName).IsIgnored;
}
public static void AddStreamerToIgnoreList(string streamerName)
{
UIStreamer.GetCreateStreamer(streamerName).IsIgnored = true;
DataStore.GetInstance().Save();
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TwitchDesktopNotifications.Core
{
public interface Singleton
{
}
public class SingletonFactory<T> where T : Singleton, new()
{
public static Dictionary<String, Singleton> store = new Dictionary<String, Singleton>();
public static T GetInstance(){
string name = typeof(T).FullName;
if (!store.ContainsKey(name))
{
store.Add(name, new T());
}
return (T)store[name];
}
}
}

View File

@@ -9,11 +9,30 @@ using TwitchDesktopNotifications.JsonStructure.Helix;
namespace TwitchDesktopNotifications.Core namespace TwitchDesktopNotifications.Core
{ {
internal class TwitcherRefreshException : Exception
{
public TwitcherRefreshException(string? message, Exception? innerException) : base(message, innerException) {
}
}
internal class TwitchFetcher internal class TwitchFetcher
{ {
private TwitchFetcher() { private TwitchFetcher() {
} }
ReconnectionNeeded rnFrm;
public void OpenFailedNotification()
{
if (rnFrm == null)
{
rnFrm = new ReconnectionNeeded();
}
if (rnFrm.IsActive)
{
rnFrm.Show();
}
}
public static TwitchFetcher instance { get; private set; } public static TwitchFetcher instance { get; private set; }
List <StreamsData> currentlyLive = null; List <StreamsData> currentlyLive = null;
@@ -46,36 +65,55 @@ namespace TwitchDesktopNotifications.Core
{ {
throw new Exception("Not Authenticated"); throw new Exception("Not Authenticated");
} }
if (DataStore.GetInstance().Store.Authentication.ExpiresAsDate <= DateTime.UtcNow) if (DataStore.GetInstance().Store.Authentication.ExpiresAsDate <= DateTime.UtcNow)
{ {
Refresh(); Refresh();
} }
WebRequest request = WebRequest.Create("https://api.twitch.tv/" + endpoint); try
request.Method = "GET"; {
request.Headers[HttpRequestHeader.Authorization] = String.Format("Bearer {0}", DataStore.GetInstance().Store.Authentication.AccessToken); WebRequest request = WebRequest.Create("https://api.twitch.tv/" + endpoint);
request.Headers["Client-ID"] = TwitchDetails.TwitchClientID; request.Method = "GET";
WebResponse response = request.GetResponse(); request.Headers[HttpRequestHeader.Authorization] = String.Format("Bearer {0}", DataStore.GetInstance().Store.Authentication.AccessToken);
Stream dataStream = response.GetResponseStream(); request.Headers["Client-ID"] = TwitchDetails.TwitchClientID;
StreamReader reader = new StreamReader(dataStream); WebResponse response = request.GetResponse();
string responseFromServer = reader.ReadToEnd(); Stream dataStream = response.GetResponseStream();
reader.Close(); StreamReader reader = new StreamReader(dataStream);
dataStream.Close(); string responseFromServer = reader.ReadToEnd();
response.Close(); reader.Close();
dataStream.Close();
response.Close();
return JsonSerializer.Deserialize<T>(responseFromServer); return JsonSerializer.Deserialize<T>(responseFromServer);
}
catch (TwitcherRefreshException ex)
{
OpenFailedNotification();
}
catch(Exception ex)
{
Logger.GetInstance().Writer.WriteLineAsync(ex.ToString());
}
return default(T);
} }
public void FetchCurrentUser() public void FetchCurrentUser()
{ {
try try
{ {
DataStore.GetInstance().Store.UserData = MakeRequest<User>("helix/users").Data[0]; var UserList = MakeRequest<User>("helix/users");
DataStore.GetInstance().Save(); if (UserList.Data.Count > 0) {
}catch(System.Exception ex) DataStore.GetInstance().Store.UserData = UserList.Data[0];
DataStore.GetInstance().Save();
}
}
catch (TwitcherRefreshException ex)
{ {
MessageBox.Show("Twitch Connection not authenticated you need to Reconnect it.", "Twitch Notify"); OpenFailedNotification();
}
catch (Exception ex)
{
Logger.GetInstance().Writer.WriteLineAsync(ex.ToString());
} }
} }
@@ -83,10 +121,19 @@ namespace TwitchDesktopNotifications.Core
{ {
try try
{ {
return MakeRequest<User>("helix/users?id=" + user_id).Data[0]; var Response = MakeRequest<User>("helix/users?id=" + user_id);
}catch(System.Exception ex) if (Response.Data.Count > 0)
{
return Response.Data[0];
}
}
catch (TwitcherRefreshException ex)
{ {
MessageBox.Show("Twitch Connection not authenticated you need to Reconnect it.", "Twitch Notify"); OpenFailedNotification();
}
catch (Exception ex)
{
Logger.GetInstance().Writer.WriteLineAsync(ex.ToString());
} }
return null; return null;
} }
@@ -104,7 +151,7 @@ namespace TwitchDesktopNotifications.Core
string QueryUrl = "helix/streams/followed?first=100&user_id=" + DataStore.GetInstance().Store.UserData.UserId; string QueryUrl = "helix/streams/followed?first=100&user_id=" + DataStore.GetInstance().Store.UserData.UserId;
Streams following = MakeRequest<Streams>(QueryUrl); Streams following = MakeRequest<Streams>(QueryUrl);
if (currentlyLive != null) if (following != null && currentlyLive != null)
{ {
following.Data.ForEach(x => following.Data.ForEach(x =>
{ {
@@ -124,42 +171,53 @@ namespace TwitchDesktopNotifications.Core
} }
currentlyLive = following.Data; currentlyLive = following.Data;
}catch(System.Exception ex)
{
MessageBox.Show("Twitch Connection not authenticated you need to Reconnect it.", "Twitch Notify");
} }
} catch (TwitcherRefreshException ex)
{
OpenFailedNotification();
}
catch (Exception ex)
{
Logger.GetInstance().Writer.WriteLineAsync(ex.ToString());
}
}
public void Refresh() public void Refresh()
{ {
Dictionary<string, string> postData = new Dictionary<string, string>(); try
{
Dictionary<string, string> postData = new Dictionary<string, string>();
postData["client_id"] = TwitchDetails.TwitchClientID; postData["client_id"] = TwitchDetails.TwitchClientID;
postData["client_secret"] = TwitchDetails.TwitchClientSecret; postData["client_secret"] = TwitchDetails.TwitchClientSecret;
postData["grant_type"] = "refresh_token"; postData["grant_type"] = "refresh_token";
postData["refresh_token"] = DataStore.GetInstance().Store.Authentication.RefreshToken; postData["refresh_token"] = DataStore.GetInstance().Store.Authentication.RefreshToken;
byte[] byteArray = buildPostData(postData); byte[] byteArray = buildPostData(postData);
WebRequest request = WebRequest.Create("https://id.twitch.tv/oauth2/token"); WebRequest request = WebRequest.Create("https://id.twitch.tv/oauth2/token");
request.Method = "POST"; request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded"; request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length; request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream(); Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length); dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close(); dataStream.Close();
WebResponse response = request.GetResponse(); WebResponse response = request.GetResponse();
dataStream = response.GetResponseStream(); dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream); StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd(); string responseFromServer = reader.ReadToEnd();
reader.Close(); reader.Close();
dataStream.Close(); dataStream.Close();
response.Close(); response.Close();
DataStore.GetInstance().Store.Authentication = JsonSerializer.Deserialize<Authentication>(responseFromServer); DataStore.GetInstance().Store.Authentication = JsonSerializer.Deserialize<Authentication>(responseFromServer);
DateTime unixStart = DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc); DateTime unixStart = DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc);
DataStore.GetInstance().Store.Authentication.ExpiresAt = (long)Math.Floor((DateTime.Now.AddSeconds(DataStore.GetInstance().Store.Authentication.ExpiresSeconds) - unixStart).TotalMilliseconds); DataStore.GetInstance().Store.Authentication.ExpiresAt = (long)Math.Floor((DateTime.Now.AddSeconds(DataStore.GetInstance().Store.Authentication.ExpiresSeconds) - unixStart).TotalMilliseconds);
DataStore.GetInstance().Save(); DataStore.GetInstance().Save();
}catch(Exception e)
{
throw new TwitcherRefreshException("Unable to refresh", e);
}
} }
async public void BeginConnection() async public void BeginConnection()

View File

@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using System.Windows.Documents;
namespace TwitchDesktopNotifications.Core
{
public class UIStreamer
{
public UIStreamer() {
}
public static UIStreamer GetCreateStreamer(string name)
{
if (DataStore.GetInstance().Store.SteamersToIgnore == null)
{
DataStore.GetInstance().Store.SteamersToIgnore = new JsonStructure.SteamersToIgnore();
}
if (DataStore.GetInstance().Store.SteamersToIgnore.Streamers == null)
{
DataStore.GetInstance().Store.SteamersToIgnore.Streamers = new List<UIStreamer>();
}
UIStreamer strmr = null;
try
{
strmr = DataStore.GetInstance().Store.SteamersToIgnore.Streamers.Where((UIStreamer strmr) => strmr.Name == name).First();
}
catch { }
finally
{
if (strmr == null)
{
strmr = new UIStreamer() { IsIgnored = false, Name = name };
DataStore.GetInstance().Store.SteamersToIgnore.Streamers.Add(strmr);
DataStore.GetInstance().Save();
}
}
return strmr;
}
[JsonIgnore]
public List<UIStreamer> StreamersToIgnore
{
get
{
return DataStore.GetInstance().Store.SteamersToIgnore.Streamers;
}
}
[JsonPropertyName("IsIgnored")]
public bool IsIgnored { get; set; } = false;
[JsonPropertyName("StreamerName")]
public string Name { get; set; }
[JsonIgnore]
public string Link {
get {
return String.Format("https://www.twitch.tv/{0}", Name);
}
}
}
}

View File

@@ -5,23 +5,12 @@ using System.IO;
namespace TwitchDesktopNotifications.Core namespace TwitchDesktopNotifications.Core
{ {
internal class WebServer public class WebServer : SingletonFactory<WebServer>, Singleton
{ {
public int Port = 32584; public int Port = 32584;
private HttpListener listener; private HttpListener listener;
private static WebServer Instance;
public static WebServer GetInstance()
{
if(Instance == null)
{
Instance= new WebServer();
}
return Instance;
}
public String TwitchCode { get; private set; } public String TwitchCode { get; private set; }
public String TwitchState { get; set; } public String TwitchState { get; set; }

View File

@@ -1,14 +1,12 @@
using System.Text.Json; using System.Text.Json;
using TwitchDesktopNotifications.JsonStructure; using TwitchDesktopNotifications.JsonStructure;
using System.IO; using System.IO;
using TwitchDesktopNotifications.Core;
namespace TwitchDesktopNotifications namespace TwitchDesktopNotifications
{ {
internal class DataStore public class DataStore : SingletonFactory<DataStore>, Singleton
{ {
private DataStore() { }
public static DataStore Instance { get; private set; }
private Store _store; private Store _store;
public JsonStructure.Store Store { public JsonStructure.Store Store {
get { get {
@@ -25,15 +23,6 @@ namespace TwitchDesktopNotifications
public bool isLoaded { get; private set; } public bool isLoaded { get; private set; }
public static DataStore GetInstance()
{
if(Instance == null)
{
Instance = new DataStore();
}
return Instance;
}
public void Save() public void Save()
{ {
String FilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TwitchNotify"); String FilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TwitchNotify");
@@ -41,29 +30,30 @@ namespace TwitchDesktopNotifications
string fileContent = JsonSerializer.Serialize<JsonStructure.Store>(Store); string fileContent = JsonSerializer.Serialize<JsonStructure.Store>(Store);
Console.WriteLine("I'm trying to save:");
Console.WriteLine(fileContent);
Console.WriteLine("to {0}", FilePath + "/" + FileName);
Directory.CreateDirectory(FilePath); Directory.CreateDirectory(FilePath);
File.WriteAllText(FilePath + "/" + FileName, fileContent); File.WriteAllText(FilePath + "/" + FileName, fileContent);
} }
public void Load() { public void Load() {
String FilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TwitchNotify"); if (!isLoaded)
String FileName = "store.json";
Directory.CreateDirectory(FilePath);
if(File.Exists(FilePath+"/"+ FileName)) {
string fileContent = File.ReadAllText(FilePath+"/"+ FileName);
Store = JsonSerializer.Deserialize<JsonStructure.Store>(fileContent);
}
else
{ {
Store = new JsonStructure.Store(); String FilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TwitchNotify");
String FileName = "store.json";
Directory.CreateDirectory(FilePath);
if (File.Exists(FilePath + "/" + FileName))
{
string fileContent = File.ReadAllText(FilePath + "/" + FileName);
Store = JsonSerializer.Deserialize<JsonStructure.Store>(fileContent);
}
else
{
Store = new JsonStructure.Store();
}
isLoaded = true;
} }
isLoaded= true;
} }
} }
} }

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace TwitchDesktopNotifications.JsonStructure namespace TwitchDesktopNotifications.JsonStructure
{ {
internal class Authentication public class Authentication
{ {
[JsonPropertyName("access_token")] [JsonPropertyName("access_token")]
public string AccessToken { get; set; } public string AccessToken { get; set; }

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace TwitchDesktopNotifications.JsonStructure.Helix namespace TwitchDesktopNotifications.JsonStructure.Helix
{ {
internal class Pagination public class Pagination
{ {
public Pagination() { } public Pagination() { }

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace TwitchDesktopNotifications.JsonStructure.Helix namespace TwitchDesktopNotifications.JsonStructure.Helix
{ {
internal class Streams public class Streams
{ {
public Streams() { } public Streams() { }

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace TwitchDesktopNotifications.JsonStructure.Helix namespace TwitchDesktopNotifications.JsonStructure.Helix
{ {
internal class StreamsData public class StreamsData
{ {
public StreamsData() { } public StreamsData() { }

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace TwitchDesktopNotifications.JsonStructure.Helix namespace TwitchDesktopNotifications.JsonStructure.Helix
{ {
internal class User public class User
{ {
public User() { } public User() { }

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace TwitchDesktopNotifications.JsonStructure.Helix namespace TwitchDesktopNotifications.JsonStructure.Helix
{ {
internal class UserData public class UserData
{ {
public UserData() { } public UserData() { }

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace TwitchDesktopNotifications.JsonStructure.Helix namespace TwitchDesktopNotifications.JsonStructure.Helix
{ {
internal class UserFollows public class UserFollows
{ {
public UserFollows() { } public UserFollows() { }

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace TwitchDesktopNotifications.JsonStructure.Helix namespace TwitchDesktopNotifications.JsonStructure.Helix
{ {
internal class UsersFollowsData public class UsersFollowsData
{ {
public UsersFollowsData() { } public UsersFollowsData() { }

View File

@@ -0,0 +1,11 @@
using System.Text.Json.Serialization;
using TwitchDesktopNotifications.Core;
namespace TwitchDesktopNotifications.JsonStructure
{
public class SteamersToIgnore
{
[JsonPropertyName("IgnoredStreamers")]
public List<UIStreamer> Streamers { get; set; } = new List<UIStreamer>();
}
}

View File

@@ -8,14 +8,28 @@ using TwitchDesktopNotifications.JsonStructure.Helix;
namespace TwitchDesktopNotifications.JsonStructure namespace TwitchDesktopNotifications.JsonStructure
{ {
internal class Store public class Store
{ {
public Store() { } public Store() { }
[JsonPropertyName("ignore")]
public SteamersToIgnore ignore { get; set; }
[JsonPropertyName("authentication")] [JsonPropertyName("authentication")]
public Authentication Authentication { get; set; } public Authentication Authentication { get; set; }
[JsonPropertyName("user_data")] [JsonPropertyName("user_data")]
public UserData UserData { get; set; } public UserData UserData { get; set; }
[JsonIgnore]
public SteamersToIgnore SteamersToIgnore {
get {
if(ignore == null) { ignore = new SteamersToIgnore(); }
return ignore;
}
set {
ignore = value;
}
}
} }
} }

View File

@@ -0,0 +1,50 @@
<Window x:Class="TwitchDesktopNotifications.ManageIgnores"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TwitchDesktopNotifications"
xmlns:core="clr-namespace:TwitchDesktopNotifications.Core"
mc:Ignorable="d"
Title="Manage Ignored Streamers" Height="435" Width="395" ResizeMode="NoResize">
<Window.DataContext>
<core:UIStreamer />
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition Height="30" />
<RowDefinition Height="10" />
<RowDefinition Height="300" />
<RowDefinition Height="10" />
<RowDefinition Height="25" />
<RowDefinition Height="10" />
</Grid.RowDefinitions>
<DataGrid
Grid.Column="1" Grid.ColumnSpan="3"
Grid.RowSpan="1" Grid.Row="3"
x:Name="dgrdIgnore" ItemsSource="{Binding StreamersToIgnore}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Streamer Name" Binding="{Binding Name}" IsReadOnly="True" />
<DataGridHyperlinkColumn Header="Streamer Link" Binding="{Binding Link}" IsReadOnly="True" />
<DataGridCheckBoxColumn Header="Ignore" Binding="{Binding IsIgnored}" IsReadOnly="False">
<DataGridCheckBoxColumn.CellStyle>
<Style>
<EventSetter Event="CheckBox.Checked" Handler="OnChecked" />
</Style>
</DataGridCheckBoxColumn.CellStyle>
</DataGridCheckBoxColumn>
</DataGrid.Columns>
</DataGrid>
<Button Content="Close" Grid.Column="3" Grid.Row="5" Click="CloseBtn_Click" />
<TextBlock Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="3" TextWrapping="Wrap" Text="Changes to the ignore list are automatically saved." VerticalAlignment="Top"/>
<TextBlock Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="3" TextWrapping="Wrap" Text="If you can't see a streamer Twitch Notify has not seen them." VerticalAlignment="Bottom"/>
</Grid>
</Window>

View File

@@ -0,0 +1,30 @@
using System.Windows;
using System.Windows.Forms;
using TwitchDesktopNotifications.Core;
namespace TwitchDesktopNotifications
{
/// <summary>
/// Interaction logic for ManageIgnores.xaml
/// </summary>
public partial class ManageIgnores : Window
{
private bool updated = false;
public ManageIgnores()
{
InitializeComponent();
}
List<UIStreamer> StreamersToIgnore = DataStore.GetInstance().Store.SteamersToIgnore.Streamers;
private void CloseBtn_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
private void OnChecked(object sender, RoutedEventArgs e)
{
updated= true;
}
}
}

View File

@@ -18,6 +18,7 @@ internal class Program
private static NotifyIcon notifyIcon; private static NotifyIcon notifyIcon;
private static ContextMenuStrip cms; private static ContextMenuStrip cms;
private static ManageIgnores manageIgnores;
public static void Ws_CodeRecived(object? sender, EventArgs e) public static void Ws_CodeRecived(object? sender, EventArgs e)
{ {
@@ -45,6 +46,21 @@ internal class Program
TriggerAuthentication(); TriggerAuthentication();
} }
protected static void ManageIgnores_Click(object? sender, System.EventArgs e)
{
if (manageIgnores == null) {
manageIgnores = new ManageIgnores();
manageIgnores.Closed += ManageIgnores_Closed;
}
manageIgnores.Show();
manageIgnores.Focus();
}
private static void ManageIgnores_Closed(object? sender, EventArgs e)
{
manageIgnores = null;
}
protected static void Quit_Click(object? sender, System.EventArgs e) protected static void Quit_Click(object? sender, System.EventArgs e)
{ {
notifyIcon.Visible = false; notifyIcon.Visible = false;
@@ -62,12 +78,13 @@ internal class Program
{ {
if (isConnecting) if (isConnecting)
{ {
MessageBox.Show("Twitch Connection not authenticated you need to Reconnect it.", "Twitch Notify"); TwitchFetcher.GetInstance().OpenFailedNotification();
} }
} }
} }
private static async Task Main(string[] args) [STAThread]
private static void Main(string[] args)
{ {
try try
{ {
@@ -78,7 +95,8 @@ internal class Program
notifyIcon.Text = "Twitch Notify"; notifyIcon.Text = "Twitch Notify";
cms = new ContextMenuStrip(); cms = new ContextMenuStrip();
cms.Items.Add(new ToolStripMenuItem("Manage Ignores", null, new EventHandler(ManageIgnores_Click)));
cms.Items.Add(new ToolStripSeparator());
cms.Items.Add(new ToolStripMenuItem("Reconnect", null, new EventHandler(Reconnect_Click))); cms.Items.Add(new ToolStripMenuItem("Reconnect", null, new EventHandler(Reconnect_Click)));
cms.Items.Add(new ToolStripSeparator()); cms.Items.Add(new ToolStripSeparator());
cms.Items.Add(new ToolStripMenuItem("Quit", null, new EventHandler(Quit_Click), "Quit")); cms.Items.Add(new ToolStripMenuItem("Quit", null, new EventHandler(Quit_Click), "Quit"));
@@ -91,7 +109,7 @@ internal class Program
TriggerAuthentication(); TriggerAuthentication();
} }
new Thread(() => Thread thread = new Thread(() =>
{ {
while (true) while (true)
{ {
@@ -101,12 +119,14 @@ internal class Program
TwitchFetcher.GetInstance().GetLiveFollowingUsers(); TwitchFetcher.GetInstance().GetLiveFollowingUsers();
} }
} }
}).Start(); });
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
Application.Run(); Application.Run();
} }
catch (Exception e) { catch (Exception e) {
Console.WriteLine(e.ToString()); Logger.GetInstance().Writer.WriteLineAsync(e.ToString());
} }
} }

View File

@@ -0,0 +1,27 @@
<Window x:Class="TwitchDesktopNotifications.ReconnectionNeeded"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TwitchDesktopNotifications"
mc:Ignorable="d"
Title="Twitch Disconnected" Height="140" Width="335" x:Name="reconnectionNeededWin">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition Height="40" />
<RowDefinition Height="10" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<TextBlock TextWrapping="Wrap" VerticalAlignment="Top" TextAlignment="Center" Text="We have been unable to refresh your twitch connection" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="3"/>
<TextBlock TextWrapping="Wrap" VerticalAlignment="Center" TextAlignment="Center" Text="Don't worry you just need to reconnect" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="3"/>
<Button Content="Thanks" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="2" Grid.Row="3" Padding="5" Click="Button_Click"/>
</Grid>
</Window>

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace TwitchDesktopNotifications
{
/// <summary>
/// Interaction logic for ReconnectionNeeded.xaml
/// </summary>
public partial class ReconnectionNeeded : Window
{
public ReconnectionNeeded()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
}

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
<ItemGroup>
<Compile Update="ManageIgnores.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="ReconnectionNeeded.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Page Update="ManageIgnores.xaml">
<SubType>Designer</SubType>
</Page>
<Page Update="ReconnectionNeeded.xaml">
<SubType>Designer</SubType>
</Page>
</ItemGroup>
</Project>