Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0af2d24b4c | ||
|
|
7946c8ec37 | ||
|
|
e9f291f6f7 | ||
|
|
77cae0c9c8 | ||
|
|
6ff5c89e45 | ||
|
|
afc4aa0d29 | ||
|
|
3ccdbbdf57 | ||
|
|
b09eb0a641 | ||
|
|
36ad4fff02 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@
|
|||||||
/TwitchDesktopNotifications/obj
|
/TwitchDesktopNotifications/obj
|
||||||
/.vs
|
/.vs
|
||||||
/TwitchDesktopNotifications/App.config
|
/TwitchDesktopNotifications/App.config
|
||||||
|
/TwitchDesktopNotifications/TwitchDetails.cs
|
||||||
|
|||||||
38
Readme.md
38
Readme.md
@@ -1,7 +1,5 @@
|
|||||||
# Twitch Notify
|
# Twitch Notify
|
||||||
## not affiliated with Twitch or Amazon
|
## Not affiliated with Twitch or Amazon
|
||||||
|
|
||||||
[](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
|
||||||
|
|||||||
@@ -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();
|
||||||
|
if (!File.Exists(FilePath + "/" + fileNameProfilePic))
|
||||||
|
{
|
||||||
(new WebClient()).DownloadFile(new Uri(profilePic), 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) { }
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user