9 Commits

7 changed files with 117 additions and 77 deletions

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@
/TwitchDesktopNotifications/obj /TwitchDesktopNotifications/obj
/.vs /.vs
/TwitchDesktopNotifications/App.config /TwitchDesktopNotifications/App.config
/TwitchDesktopNotifications/TwitchDetails.cs

View File

@@ -1,7 +1,5 @@
# Twitch Notify # Twitch Notify
## not affiliated with Twitch or Amazon ## Not affiliated with Twitch or Amazon
[![Build Status](https://travis-ci.org/joemccann/dillinger.svg?branch=master)](https://travis-ci.org/joemccann/dillinger)
## Installation ## Installation
Twitch Notify Requires [.NET 6 Desktop Runtime](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-6.0.13-windows-x64-installer). Twitch Notify Requires [.NET 6 Desktop Runtime](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-6.0.13-windows-x64-installer).
@@ -11,19 +9,33 @@
Want to contribute? Great! Want to contribute? Great!
Project is built using Visual Studios 2022, must have Windows 10.0.17763 SDK installed Project is built using Visual Studios 2022,
You must create a `App.config` file inside `TwitchDesktopNotifications` project. You need to create Application to obtain a ID and Secret on [Twitch Developer Console](https://dev.twitch.tv/console)
```xml Add a new C# Class to the project named `TwitchDetails.cs` add the following code with your ID and Secret
<?xml version="1.0" encoding="utf-8" ?> ```cs
<configuration> namespace TwitchDesktopNotifications
<appSettings> {
<add key="TwitchClientID" value="" /> static public class TwitchDetails
<add key="TwitchClientSecret" value="" /> {
</appSettings> public static string TwitchClientID = "";
</configuration> public static string TwitchClientSecret = "";
}
}
``` ```
### CommunityToolkit 8.0.0 Pre-release
Project Requests `CommunityToolkit-MainLatest` NuGET Package Source
1. Tool > NuGET Package Manager > Package Manager Settings
2. Click on Package Source (just below the select General in the Left hand column
3. Click the + icon top right
5. 4. Enter the Name `CommunityToolkit-MainLatest` and Source `https://pkgs.dev.azure.com/dotnet/CommunityToolkit/_packaging/CommunityToolkit-MainLatest/nuget/v3/index.json`
6. Click Update
7. Click Ok
## License ## License
MIT MIT

View File

@@ -9,6 +9,7 @@ using System.IO;
using Windows.Foundation.Collections; using Windows.Foundation.Collections;
using System.Diagnostics; using System.Diagnostics;
using System.ComponentModel; using System.ComponentModel;
using Windows.UI.Notifications;
namespace TwitchDesktopNotifications.Core namespace TwitchDesktopNotifications.Core
{ {
@@ -22,10 +23,18 @@ namespace TwitchDesktopNotifications.Core
try try
{ {
if (
// action is defined and set to watch
( args.Contains("action") && args["action"] == "watch" )
||
// action is not defined so the user just generally clicked on the notification
!args.Contains("action")
){
Process myProcess = new Process(); Process myProcess = new Process();
myProcess.StartInfo.UseShellExecute = true; myProcess.StartInfo.UseShellExecute = true;
myProcess.StartInfo.FileName = args["streamerUrl"]; myProcess.StartInfo.FileName = args["streamerUrl"];
myProcess.Start(); myProcess.Start();
}
}catch(Exception ex) { } }catch(Exception ex) { }
}; };
} }
@@ -49,7 +58,10 @@ namespace TwitchDesktopNotifications.Core
// download there profile picture // download there profile picture
string fileNameProfilePic = profilePic.Split("/").Last(); string fileNameProfilePic = profilePic.Split("/").Last();
(new WebClient()).DownloadFile(new Uri(profilePic), FilePath+"/"+ fileNameProfilePic); if (!File.Exists(FilePath + "/" + fileNameProfilePic))
{
(new 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();
@@ -59,6 +71,7 @@ namespace TwitchDesktopNotifications.Core
var builder = new ToastContentBuilder() var builder = new ToastContentBuilder()
.AddArgument("streamerUrl", streamerUrl) .AddArgument("streamerUrl", streamerUrl)
.AddArgument("thumbnail_path", FilePath + "/" + fileNameThumbnailPic)
.AddText(streamerName + " is now live on Twitch") .AddText(streamerName + " is now live on Twitch")
.AddHeroImage(new Uri("file://" + (FilePath + "/" + fileNameThumbnailPic).Replace("\\", "/"))) .AddHeroImage(new Uri("file://" + (FilePath + "/" + fileNameThumbnailPic).Replace("\\", "/")))
.AddAppLogoOverride(new Uri("file://" + (FilePath + "/" + fileNameProfilePic).Replace("\\", "/")), ToastGenericAppLogoCrop.Circle) .AddAppLogoOverride(new Uri("file://" + (FilePath + "/" + fileNameProfilePic).Replace("\\", "/")), ToastGenericAppLogoCrop.Circle)
@@ -77,9 +90,22 @@ namespace TwitchDesktopNotifications.Core
builder.Show(toast => builder.Show(toast =>
{ {
toast.ExpirationTime = DateTime.Now.AddSeconds(15); toast.ExpirationTime = DateTime.Now.AddSeconds(15);
toast.Dismissed += (ToastNotification sender, ToastDismissedEventArgs args) =>
{
try
{
File.Delete(FilePath + "/" + fileNameThumbnailPic);
}catch(Exception) { }
};
toast.Activated += (ToastNotification sender, object args) =>
{
try
{
File.Delete(FilePath + "/" + fileNameThumbnailPic);
}
catch (Exception) { }
};
}); });
} }
} }
} }

View File

@@ -1,33 +1,21 @@
using ABI.System; using System.Diagnostics;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq;
using System.Net; using System.Net;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using System.Web; using System.Web;
using TwitchDesktopNotifications.JsonStructure; using TwitchDesktopNotifications.JsonStructure;
using TwitchDesktopNotifications.JsonStructure.Helix; using TwitchDesktopNotifications.JsonStructure.Helix;
using Windows.ApplicationModel.Background;
namespace TwitchDesktopNotifications.Core namespace TwitchDesktopNotifications.Core
{ {
internal class TwitchFetcher internal class TwitchFetcher
{ {
private TwitchFetcher() { } private TwitchFetcher() {
}
public static TwitchFetcher instance { get; private set; } public static TwitchFetcher instance { get; private set; }
string TwitchClientID = ConfigurationManager.AppSettings["TwitchClientID"];
string TwitchClientSecret = ConfigurationManager.AppSettings["TwitchClientSecret"];
List <StreamsData> currentlyLive = null; List <StreamsData> currentlyLive = null;
public string guid { get; private set; } public string guid { get; private set; }
@@ -54,6 +42,10 @@ namespace TwitchDesktopNotifications.Core
private T MakeRequest<T>(string endpoint) private T MakeRequest<T>(string endpoint)
{ {
if (DataStore.GetInstance().Store == null)
{
throw new Exception("Not Authenticated");
}
if (DataStore.GetInstance().Store.Authentication.ExpiresAsDate <= DateTime.UtcNow) if (DataStore.GetInstance().Store.Authentication.ExpiresAsDate <= DateTime.UtcNow)
{ {
@@ -63,7 +55,7 @@ namespace TwitchDesktopNotifications.Core
WebRequest request = WebRequest.Create("https://api.twitch.tv/" + endpoint); WebRequest request = WebRequest.Create("https://api.twitch.tv/" + endpoint);
request.Method = "GET"; request.Method = "GET";
request.Headers[HttpRequestHeader.Authorization] = String.Format("Bearer {0}", DataStore.GetInstance().Store.Authentication.AccessToken); request.Headers[HttpRequestHeader.Authorization] = String.Format("Bearer {0}", DataStore.GetInstance().Store.Authentication.AccessToken);
request.Headers["Client-ID"] = TwitchClientID; request.Headers["Client-ID"] = TwitchDetails.TwitchClientID;
WebResponse response = request.GetResponse(); WebResponse response = request.GetResponse();
Stream dataStream = response.GetResponseStream(); Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream); StreamReader reader = new StreamReader(dataStream);
@@ -83,7 +75,7 @@ namespace TwitchDesktopNotifications.Core
DataStore.GetInstance().Save(); DataStore.GetInstance().Save();
}catch(System.Exception ex) }catch(System.Exception ex)
{ {
Environment.Exit(1); MessageBox.Show("Twitch Connection not authenticated you need to Reconnect it.", "Twitch Notify");
} }
} }
@@ -94,7 +86,7 @@ namespace TwitchDesktopNotifications.Core
return MakeRequest<User>("helix/users?id=" + user_id).Data[0]; return MakeRequest<User>("helix/users?id=" + user_id).Data[0];
}catch(System.Exception ex) }catch(System.Exception ex)
{ {
Environment.Exit(1); MessageBox.Show("Twitch Connection not authenticated you need to Reconnect it.", "Twitch Notify");
} }
return null; return null;
} }
@@ -134,7 +126,7 @@ namespace TwitchDesktopNotifications.Core
currentlyLive = following.Data; currentlyLive = following.Data;
}catch(System.Exception ex) }catch(System.Exception ex)
{ {
Environment.Exit(1); MessageBox.Show("Twitch Connection not authenticated you need to Reconnect it.", "Twitch Notify");
} }
} }
@@ -142,8 +134,8 @@ namespace TwitchDesktopNotifications.Core
{ {
Dictionary<string, string> postData = new Dictionary<string, string>(); Dictionary<string, string> postData = new Dictionary<string, string>();
postData["client_id"] = TwitchClientID; postData["client_id"] = TwitchDetails.TwitchClientID;
postData["client_secret"] = 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;
@@ -176,7 +168,7 @@ namespace TwitchDesktopNotifications.Core
WebServer.GetInstance().TwitchState = guid; WebServer.GetInstance().TwitchState = guid;
Process myProcess = new Process(); Process myProcess = new Process();
myProcess.StartInfo.UseShellExecute = true; myProcess.StartInfo.UseShellExecute = true;
myProcess.StartInfo.FileName = String.Format("https://id.twitch.tv/oauth2/authorize?&redirect_uri=http://localhost:32584/twitchRedirect&scope=user:read:subscriptions%20user:read:follows%20user:read:email%20openid&response_type=code&state={0}&nonce={1}&client_id={2}", guid, guid, TwitchClientID); myProcess.StartInfo.FileName = String.Format("https://id.twitch.tv/oauth2/authorize?&redirect_uri=http://localhost:32584/twitchRedirect&scope=user:read:subscriptions%20user:read:follows%20user:read:email%20openid&response_type=code&state={0}&nonce={1}&client_id={2}", guid, guid, TwitchDetails.TwitchClientID);
myProcess.Start(); myProcess.Start();
} }
@@ -184,8 +176,8 @@ namespace TwitchDesktopNotifications.Core
{ {
Dictionary<string, string> postData = new Dictionary<string, string>(); Dictionary<string, string> postData = new Dictionary<string, string>();
postData["client_id"] = TwitchClientID; postData["client_id"] = TwitchDetails.TwitchClientID;
postData["client_secret"] = TwitchClientSecret; postData["client_secret"] = TwitchDetails.TwitchClientSecret;
postData["grant_type"] = "authorization_code"; postData["grant_type"] = "authorization_code";
postData["redirect_uri"] = "http://localhost:32584/twitchRedirect"; postData["redirect_uri"] = "http://localhost:32584/twitchRedirect";
postData["code"] = code; postData["code"] = code;

View File

@@ -40,6 +40,10 @@ namespace TwitchDesktopNotifications
String FileName = "store.json"; String FileName = "store.json";
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);
} }

View File

@@ -1,5 +1,6 @@
// See https://aka.ms/new-console-template for more information // See https://aka.ms/new-console-template for more information
using System.Drawing; using System.Drawing;
using System.Reflection.Metadata;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text.Json; using System.Text.Json;
using System.Windows.Controls; using System.Windows.Controls;
@@ -18,7 +19,6 @@ internal class Program
private static NotifyIcon notifyIcon; private static NotifyIcon notifyIcon;
private static ContextMenuStrip cms; private static ContextMenuStrip cms;
public static void Ws_CodeRecived(object? sender, EventArgs e) public static void Ws_CodeRecived(object? sender, EventArgs e)
{ {
ws.CodeRecived -= Ws_CodeRecived; ws.CodeRecived -= Ws_CodeRecived;
@@ -60,25 +60,22 @@ internal class Program
TwitchFetcher.GetInstance().BeginConnection(); TwitchFetcher.GetInstance().BeginConnection();
if (DataStore.GetInstance().Store.Authentication == null) if (DataStore.GetInstance().Store.Authentication == null)
{ {
var timerForCrash = new PeriodicTimer(TimeSpan.FromSeconds(10));
await timerForCrash.WaitForNextTickAsync();
if (isConnecting) if (isConnecting)
{ {
MessageBox.Show("Twitch Connection not authenticated Exiting for saftey.", "Twitch Notify"); MessageBox.Show("Twitch Connection not authenticated you need to Reconnect it.", "Twitch Notify");
notifyIcon.Visible = false;
notifyIcon.Dispose();
Environment.Exit(1);
} }
} }
} }
private static async Task Main(string[] args) private static async Task Main(string[] args)
{
try
{ {
var timer = new PeriodicTimer(TimeSpan.FromSeconds(10)); var timer = new PeriodicTimer(TimeSpan.FromSeconds(10));
notifyIcon = new NotifyIcon(); notifyIcon = new NotifyIcon();
notifyIcon.Icon = new Icon("Assets/icon.ico"); notifyIcon.Icon = new Icon("Assets/icon.ico");
notifyIcon.Text = "Notify"; notifyIcon.Text = "Twitch Notify";
cms = new ContextMenuStrip(); cms = new ContextMenuStrip();
@@ -99,11 +96,18 @@ internal class Program
while (true) while (true)
{ {
Thread.Sleep(10000); Thread.Sleep(10000);
if (DataStore.GetInstance().Store != null)
{
TwitchFetcher.GetInstance().GetLiveFollowingUsers(); TwitchFetcher.GetInstance().GetLiveFollowingUsers();
} }
}
}).Start(); }).Start();
Application.Run(); Application.Run();
}
catch (Exception e) {
Console.WriteLine(e.ToString());
}
} }
} }

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
@@ -11,6 +11,7 @@
<AssemblyName>Twitch Notify</AssemblyName> <AssemblyName>Twitch Notify</AssemblyName>
<UseWPF>True</UseWPF> <UseWPF>True</UseWPF>
<UseWindowsForms>True</UseWindowsForms> <UseWindowsForms>True</UseWindowsForms>
<UserSecretsId>2dfb7064-609b-41c3-a80d-a9e4d842a55d</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>