Added Support for Debug Logging
Updated a couple of variables for better memory use. Added Support for ignoring specific streamers Moved to using a SingletonFactory for Singlton Classes No Longer Using MessageBox for disconnected message Added better detection for disconnected to stop it poping with other problems Added Window and menu option to open window to manage ignored streamers
This commit is contained in:
38
TwitchDesktopNotifications/Core/Logger.cs
Normal file
38
TwitchDesktopNotifications/Core/Logger.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,12 +10,14 @@ using Windows.Foundation.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.ComponentModel;
|
||||
using Windows.UI.Notifications;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace TwitchDesktopNotifications.Core
|
||||
{
|
||||
internal class Notification
|
||||
public class Notification : SingletonFactory<Notification>, Singleton
|
||||
{
|
||||
private Notification() {
|
||||
private WebClient webClient = new WebClient();
|
||||
public Notification() {
|
||||
ToastNotificationManagerCompat.OnActivated += toastArgs =>
|
||||
{
|
||||
// Obtain the arguments from the notification
|
||||
@@ -34,22 +36,16 @@ namespace TwitchDesktopNotifications.Core
|
||||
myProcess.StartInfo.UseShellExecute = true;
|
||||
myProcess.StartInfo.FileName = args["streamerUrl"];
|
||||
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)
|
||||
{
|
||||
String FilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TwitchNotify");
|
||||
@@ -60,52 +56,64 @@ namespace TwitchDesktopNotifications.Core
|
||||
string fileNameProfilePic = profilePic.Split("/").Last();
|
||||
if (!File.Exists(FilePath + "/" + fileNameProfilePic))
|
||||
{
|
||||
(new WebClient()).DownloadFile(new Uri(profilePic), FilePath + "/" + fileNameProfilePic);
|
||||
webClient.DownloadFile(new Uri(profilePic), FilePath + "/" + fileNameProfilePic);
|
||||
}
|
||||
|
||||
// download there profile picture
|
||||
string fileNameThumbnailPic = streamThumbnail.Split("/").Last();
|
||||
(new WebClient()).DownloadFile(new Uri(streamThumbnail),
|
||||
webClient.DownloadFile(new Uri(streamThumbnail),
|
||||
FilePath + "/" + fileNameThumbnailPic
|
||||
);
|
||||
|
||||
var builder = new ToastContentBuilder()
|
||||
.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 =>
|
||||
if (NotifyManager.ShouldNotify(streamerName))
|
||||
{
|
||||
toast.ExpirationTime = DateTime.Now.AddSeconds(15);
|
||||
toast.Dismissed += (ToastNotification sender, ToastDismissedEventArgs args) =>
|
||||
var builder = new ToastContentBuilder()
|
||||
.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
|
||||
{
|
||||
File.Delete(FilePath + "/" + fileNameThumbnailPic);
|
||||
}catch(Exception) { }
|
||||
};
|
||||
toast.Activated += (ToastNotification sender, object args) =>
|
||||
builder.AddText(title);
|
||||
}
|
||||
builder.Show(toast =>
|
||||
{
|
||||
try
|
||||
toast.ExpirationTime = DateTime.Now.AddSeconds(15);
|
||||
toast.Dismissed += (ToastNotification sender, ToastDismissedEventArgs args) =>
|
||||
{
|
||||
File.Delete(FilePath + "/" + fileNameThumbnailPic);
|
||||
}
|
||||
catch (Exception) { }
|
||||
};
|
||||
});
|
||||
try
|
||||
{
|
||||
File.Delete(FilePath + "/" + fileNameThumbnailPic);
|
||||
}
|
||||
catch (Exception) { }
|
||||
builder = null;
|
||||
};
|
||||
toast.Activated += (ToastNotification sender, object args) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(FilePath + "/" + fileNameThumbnailPic);
|
||||
}
|
||||
catch (Exception) { }
|
||||
builder = null;
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
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
|
||||
@@ -10,39 +12,18 @@ namespace TwitchDesktopNotifications.Core
|
||||
internal class NotifyManager
|
||||
{
|
||||
|
||||
public Boolean shouldNotify(String streamerName)
|
||||
public static Boolean ShouldNotify(String streamerName)
|
||||
{
|
||||
return notifyAll || !DataStore.GetInstance().Store.SteamersToNotify.Streamers.Contains(streamerName);
|
||||
}
|
||||
|
||||
public void AddStreamerToNotifyList(String streamerName)
|
||||
{
|
||||
DataStore.GetInstance().Store.SteamersToNotify.Streamers.Add(streamerName);
|
||||
DataStore.GetInstance().Save();
|
||||
}
|
||||
|
||||
public void RemoveStreamerToNotifyList(String streamerName)
|
||||
{
|
||||
DataStore.GetInstance().Store.SteamersToNotify.Streamers.Remove(streamerName);
|
||||
DataStore.GetInstance().Save();
|
||||
}
|
||||
|
||||
public void ClearListOfEnabled()
|
||||
{
|
||||
DataStore.GetInstance().Store.SteamersToNotify.Streamers = new List<string>();
|
||||
DataStore.GetInstance().Save();
|
||||
}
|
||||
|
||||
public bool notifyAll
|
||||
{
|
||||
get
|
||||
{
|
||||
return DataStore.GetInstance().Store.SteamersToNotify.notifyAll;
|
||||
}
|
||||
set {
|
||||
DataStore.GetInstance().Store.SteamersToNotify.notifyAll = value;
|
||||
DataStore.GetInstance().Save();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
26
TwitchDesktopNotifications/Core/SingletonFactory.cs
Normal file
26
TwitchDesktopNotifications/Core/SingletonFactory.cs
Normal 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,30 @@ using TwitchDesktopNotifications.JsonStructure.Helix;
|
||||
|
||||
namespace TwitchDesktopNotifications.Core
|
||||
{
|
||||
internal class TwitcherRefreshException : Exception
|
||||
{
|
||||
public TwitcherRefreshException(string? message, Exception? innerException) : base(message, innerException) {
|
||||
}
|
||||
}
|
||||
internal class 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; }
|
||||
|
||||
List <StreamsData> currentlyLive = null;
|
||||
@@ -46,36 +65,55 @@ namespace TwitchDesktopNotifications.Core
|
||||
{
|
||||
throw new Exception("Not Authenticated");
|
||||
}
|
||||
|
||||
if (DataStore.GetInstance().Store.Authentication.ExpiresAsDate <= DateTime.UtcNow)
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
|
||||
WebRequest request = WebRequest.Create("https://api.twitch.tv/" + endpoint);
|
||||
request.Method = "GET";
|
||||
request.Headers[HttpRequestHeader.Authorization] = String.Format("Bearer {0}", DataStore.GetInstance().Store.Authentication.AccessToken);
|
||||
request.Headers["Client-ID"] = TwitchDetails.TwitchClientID;
|
||||
WebResponse response = request.GetResponse();
|
||||
Stream dataStream = response.GetResponseStream();
|
||||
StreamReader reader = new StreamReader(dataStream);
|
||||
string responseFromServer = reader.ReadToEnd();
|
||||
reader.Close();
|
||||
dataStream.Close();
|
||||
response.Close();
|
||||
try
|
||||
{
|
||||
WebRequest request = WebRequest.Create("https://api.twitch.tv/" + endpoint);
|
||||
request.Method = "GET";
|
||||
request.Headers[HttpRequestHeader.Authorization] = String.Format("Bearer {0}", DataStore.GetInstance().Store.Authentication.AccessToken);
|
||||
request.Headers["Client-ID"] = TwitchDetails.TwitchClientID;
|
||||
WebResponse response = request.GetResponse();
|
||||
Stream dataStream = response.GetResponseStream();
|
||||
StreamReader reader = new StreamReader(dataStream);
|
||||
string responseFromServer = reader.ReadToEnd();
|
||||
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()
|
||||
{
|
||||
try
|
||||
{
|
||||
DataStore.GetInstance().Store.UserData = MakeRequest<User>("helix/users").Data[0];
|
||||
DataStore.GetInstance().Save();
|
||||
}catch(System.Exception ex)
|
||||
var UserList = MakeRequest<User>("helix/users");
|
||||
if (UserList.Data.Count > 0) {
|
||||
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
|
||||
{
|
||||
return MakeRequest<User>("helix/users?id=" + user_id).Data[0];
|
||||
}catch(System.Exception ex)
|
||||
var Response = MakeRequest<User>("helix/users?id=" + user_id);
|
||||
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;
|
||||
}
|
||||
@@ -104,7 +151,7 @@ namespace TwitchDesktopNotifications.Core
|
||||
string QueryUrl = "helix/streams/followed?first=100&user_id=" + DataStore.GetInstance().Store.UserData.UserId;
|
||||
Streams following = MakeRequest<Streams>(QueryUrl);
|
||||
|
||||
if (currentlyLive != null)
|
||||
if (following != null && currentlyLive != null)
|
||||
{
|
||||
following.Data.ForEach(x =>
|
||||
{
|
||||
@@ -124,49 +171,53 @@ namespace TwitchDesktopNotifications.Core
|
||||
}
|
||||
|
||||
currentlyLive = following.Data;
|
||||
}catch(System.Exception ex)
|
||||
{
|
||||
if (!ex.Message.Contains("Notification"))
|
||||
{
|
||||
MessageBox.Show("Twitch Connection not authenticated you need to Reconnect it.", "Twitch Notify");
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Unable to use Windows Notifications.", "Twitch Notify");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (TwitcherRefreshException ex)
|
||||
{
|
||||
OpenFailedNotification();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.GetInstance().Writer.WriteLineAsync(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
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_secret"] = TwitchDetails.TwitchClientSecret;
|
||||
postData["grant_type"] = "refresh_token";
|
||||
postData["refresh_token"] = DataStore.GetInstance().Store.Authentication.RefreshToken;
|
||||
postData["client_id"] = TwitchDetails.TwitchClientID;
|
||||
postData["client_secret"] = TwitchDetails.TwitchClientSecret;
|
||||
postData["grant_type"] = "refresh_token";
|
||||
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");
|
||||
request.Method = "POST";
|
||||
request.ContentType = "application/x-www-form-urlencoded";
|
||||
request.ContentLength = byteArray.Length;
|
||||
Stream dataStream = request.GetRequestStream();
|
||||
dataStream.Write(byteArray, 0, byteArray.Length);
|
||||
dataStream.Close();
|
||||
WebResponse response = request.GetResponse();
|
||||
dataStream = response.GetResponseStream();
|
||||
StreamReader reader = new StreamReader(dataStream);
|
||||
string responseFromServer = reader.ReadToEnd();
|
||||
reader.Close();
|
||||
dataStream.Close();
|
||||
response.Close();
|
||||
WebRequest request = WebRequest.Create("https://id.twitch.tv/oauth2/token");
|
||||
request.Method = "POST";
|
||||
request.ContentType = "application/x-www-form-urlencoded";
|
||||
request.ContentLength = byteArray.Length;
|
||||
Stream dataStream = request.GetRequestStream();
|
||||
dataStream.Write(byteArray, 0, byteArray.Length);
|
||||
dataStream.Close();
|
||||
WebResponse response = request.GetResponse();
|
||||
dataStream = response.GetResponseStream();
|
||||
StreamReader reader = new StreamReader(dataStream);
|
||||
string responseFromServer = reader.ReadToEnd();
|
||||
reader.Close();
|
||||
dataStream.Close();
|
||||
response.Close();
|
||||
|
||||
DataStore.GetInstance().Store.Authentication = JsonSerializer.Deserialize<Authentication>(responseFromServer);
|
||||
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().Save();
|
||||
DataStore.GetInstance().Store.Authentication = JsonSerializer.Deserialize<Authentication>(responseFromServer);
|
||||
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().Save();
|
||||
}catch(Exception e)
|
||||
{
|
||||
throw new TwitcherRefreshException("Unable to refresh", e);
|
||||
}
|
||||
}
|
||||
|
||||
async public void BeginConnection()
|
||||
|
||||
69
TwitchDesktopNotifications/Core/UIStreamer.cs
Normal file
69
TwitchDesktopNotifications/Core/UIStreamer.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,23 +5,12 @@ using System.IO;
|
||||
|
||||
namespace TwitchDesktopNotifications.Core
|
||||
{
|
||||
internal class WebServer
|
||||
public class WebServer : SingletonFactory<WebServer>, Singleton
|
||||
{
|
||||
public int Port = 32584;
|
||||
|
||||
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 TwitchState { get; set; }
|
||||
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
using System.Text.Json;
|
||||
using TwitchDesktopNotifications.JsonStructure;
|
||||
using System.IO;
|
||||
using TwitchDesktopNotifications.Core;
|
||||
|
||||
namespace TwitchDesktopNotifications
|
||||
{
|
||||
internal class DataStore
|
||||
public class DataStore : SingletonFactory<DataStore>, Singleton
|
||||
{
|
||||
private DataStore() { }
|
||||
|
||||
public static DataStore Instance { get; private set; }
|
||||
private Store _store;
|
||||
public JsonStructure.Store Store {
|
||||
get {
|
||||
@@ -25,15 +23,6 @@ namespace TwitchDesktopNotifications
|
||||
|
||||
public bool isLoaded { get; private set; }
|
||||
|
||||
public static DataStore GetInstance()
|
||||
{
|
||||
if(Instance == null)
|
||||
{
|
||||
Instance = new DataStore();
|
||||
}
|
||||
return Instance;
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
String FilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TwitchNotify");
|
||||
@@ -41,29 +30,30 @@ namespace TwitchDesktopNotifications
|
||||
|
||||
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);
|
||||
File.WriteAllText(FilePath + "/" + FileName, fileContent);
|
||||
}
|
||||
|
||||
public void Load() {
|
||||
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
|
||||
if (!isLoaded)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace TwitchDesktopNotifications.JsonStructure
|
||||
{
|
||||
internal class Authentication
|
||||
public class Authentication
|
||||
{
|
||||
[JsonPropertyName("access_token")]
|
||||
public string AccessToken { get; set; }
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace TwitchDesktopNotifications.JsonStructure.Helix
|
||||
{
|
||||
internal class Pagination
|
||||
public class Pagination
|
||||
{
|
||||
public Pagination() { }
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace TwitchDesktopNotifications.JsonStructure.Helix
|
||||
{
|
||||
internal class Streams
|
||||
public class Streams
|
||||
{
|
||||
public Streams() { }
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace TwitchDesktopNotifications.JsonStructure.Helix
|
||||
{
|
||||
internal class StreamsData
|
||||
public class StreamsData
|
||||
{
|
||||
public StreamsData() { }
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace TwitchDesktopNotifications.JsonStructure.Helix
|
||||
{
|
||||
internal class User
|
||||
public class User
|
||||
{
|
||||
public User() { }
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace TwitchDesktopNotifications.JsonStructure.Helix
|
||||
{
|
||||
internal class UserData
|
||||
public class UserData
|
||||
{
|
||||
public UserData() { }
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace TwitchDesktopNotifications.JsonStructure.Helix
|
||||
{
|
||||
internal class UserFollows
|
||||
public class UserFollows
|
||||
{
|
||||
public UserFollows() { }
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace TwitchDesktopNotifications.JsonStructure.Helix
|
||||
{
|
||||
internal class UsersFollowsData
|
||||
public class UsersFollowsData
|
||||
{
|
||||
public UsersFollowsData() { }
|
||||
|
||||
|
||||
11
TwitchDesktopNotifications/JsonStructure/SteamersToIgnore.cs
Normal file
11
TwitchDesktopNotifications/JsonStructure/SteamersToIgnore.cs
Normal 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>();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace TwitchDesktopNotifications.JsonStructure
|
||||
{
|
||||
internal class SteamersToNotify
|
||||
{
|
||||
[JsonPropertyName("notifyAll")]
|
||||
public Boolean notifyAll = true;
|
||||
|
||||
[JsonPropertyName("notify")]
|
||||
public List<String> Streamers { get; set; } = new List<String>();
|
||||
}
|
||||
}
|
||||
@@ -8,17 +8,28 @@ using TwitchDesktopNotifications.JsonStructure.Helix;
|
||||
|
||||
namespace TwitchDesktopNotifications.JsonStructure
|
||||
{
|
||||
internal class Store
|
||||
public class Store
|
||||
{
|
||||
public Store() { }
|
||||
|
||||
[JsonPropertyName("ignore")]
|
||||
public SteamersToIgnore ignore { get; set; }
|
||||
|
||||
[JsonPropertyName("authentication")]
|
||||
public Authentication Authentication { get; set; }
|
||||
|
||||
[JsonPropertyName("user_data")]
|
||||
public UserData UserData { get; set; }
|
||||
|
||||
[JsonPropertyName("notifications_for")]
|
||||
public SteamersToNotify SteamersToNotify { get; set; };
|
||||
[JsonIgnore]
|
||||
public SteamersToIgnore SteamersToIgnore {
|
||||
get {
|
||||
if(ignore == null) { ignore = new SteamersToIgnore(); }
|
||||
return ignore;
|
||||
}
|
||||
set {
|
||||
ignore = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
50
TwitchDesktopNotifications/ManageIgnores.xaml
Normal file
50
TwitchDesktopNotifications/ManageIgnores.xaml
Normal 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>
|
||||
30
TwitchDesktopNotifications/ManageIgnores.xaml.cs
Normal file
30
TwitchDesktopNotifications/ManageIgnores.xaml.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ internal class Program
|
||||
|
||||
private static NotifyIcon notifyIcon;
|
||||
private static ContextMenuStrip cms;
|
||||
private static ManageIgnores manageIgnores;
|
||||
|
||||
public static void Ws_CodeRecived(object? sender, EventArgs e)
|
||||
{
|
||||
@@ -45,6 +46,21 @@ internal class Program
|
||||
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)
|
||||
{
|
||||
notifyIcon.Visible = false;
|
||||
@@ -62,12 +78,13 @@ internal class Program
|
||||
{
|
||||
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
|
||||
{
|
||||
@@ -78,7 +95,8 @@ internal class Program
|
||||
notifyIcon.Text = "Twitch Notify";
|
||||
|
||||
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 ToolStripSeparator());
|
||||
cms.Items.Add(new ToolStripMenuItem("Quit", null, new EventHandler(Quit_Click), "Quit"));
|
||||
@@ -91,7 +109,7 @@ internal class Program
|
||||
TriggerAuthentication();
|
||||
}
|
||||
|
||||
new Thread(() =>
|
||||
Thread thread = new Thread(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
@@ -101,12 +119,14 @@ internal class Program
|
||||
TwitchFetcher.GetInstance().GetLiveFollowingUsers();
|
||||
}
|
||||
}
|
||||
}).Start();
|
||||
});
|
||||
thread.SetApartmentState(ApartmentState.STA);
|
||||
thread.Start();
|
||||
|
||||
Application.Run();
|
||||
}
|
||||
catch (Exception e) {
|
||||
Console.WriteLine(e.ToString());
|
||||
Logger.GetInstance().Writer.WriteLineAsync(e.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
27
TwitchDesktopNotifications/ReconnectionNeeded.xaml
Normal file
27
TwitchDesktopNotifications/ReconnectionNeeded.xaml
Normal 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>
|
||||
32
TwitchDesktopNotifications/ReconnectionNeeded.xaml.cs
Normal file
32
TwitchDesktopNotifications/ReconnectionNeeded.xaml.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user