From a6124e99215193cb3589f1609d13419ec79cb468 Mon Sep 17 00:00:00 2001 From: LP Date: Fri, 8 Dec 2023 20:09:39 +0000 Subject: [PATCH] Removed youtube integration, it can be its own plugin once figured out --- .../YoutubeIntegrationComponent.razor | 143 ------------- .../Components/ScopeCollections.cs | 9 - .../Components/YoutubeLiveChat.razor | 10 - .../Components/YoutubeScopes.razor | 54 ----- .../Controllers/YoutubeController.cs | 61 ------ .../Events/OAuth/YoutubeOAuthRevokedEvent.cs | 4 - .../Events/OAuth/YoutubeOAuthSuccessEvent.cs | 4 - .../OAuth/YoutubeOAuthTokenExpiredEvent.cs | 4 - .../Extensions/IAppStateExtensions.cs | 18 -- .../Models/YoutubeOAuthAuthorizePayload.cs | 12 -- .../Models/YoutubeOAuthQuerystringPayload.cs | 12 -- .../Models/YoutubeOAuthTokenPayload.cs | 17 -- .../Models/YoutubeOAuthValidationPayload.cs | 13 -- .../Plugin/YoutubeIntegrationDescriptor.cs | 15 -- src/Strem.Youtube/Plugin/YoutubeModule.cs | 49 ----- .../Plugin/YoutubePluginSettings.cs | 9 - .../Plugin/YoutubePluginStartup.cs | 111 ---------- .../Client/AccessTokenUserCredential.cs | 30 --- .../Client/IObservableYoutubeClient.cs | 14 -- .../Client/ObservableYoutubeClient.cs | 51 ----- .../Services/OAuth/IYoutubeOAuthClient.cs | 11 - .../Services/OAuth/YoutubeOAuthClient.cs | 200 ------------------ src/Strem.Youtube/Strem.Youtube.csproj | 34 --- src/Strem.Youtube/Types/Scopes.cs | 8 - src/Strem.Youtube/Variables/YoutubeVars.cs | 23 -- .../Views/Youtube/OAuthFailed.cshtml | 33 --- .../Views/Youtube/OAuthSuccess.cshtml | 28 --- src/Strem.Youtube/_Imports.razor | 10 - src/Strem.sln | 7 - src/Strem/Application/PluginHandler.cs | 2 - src/Strem/Strem.csproj | 1 - src/Strem/wwwroot/css/app-styles.less | 3 - 32 files changed, 1000 deletions(-) delete mode 100644 src/Strem.Youtube/Components/Integrations/YoutubeIntegrationComponent.razor delete mode 100644 src/Strem.Youtube/Components/ScopeCollections.cs delete mode 100644 src/Strem.Youtube/Components/YoutubeLiveChat.razor delete mode 100644 src/Strem.Youtube/Components/YoutubeScopes.razor delete mode 100644 src/Strem.Youtube/Controllers/YoutubeController.cs delete mode 100644 src/Strem.Youtube/Events/OAuth/YoutubeOAuthRevokedEvent.cs delete mode 100644 src/Strem.Youtube/Events/OAuth/YoutubeOAuthSuccessEvent.cs delete mode 100644 src/Strem.Youtube/Events/OAuth/YoutubeOAuthTokenExpiredEvent.cs delete mode 100644 src/Strem.Youtube/Extensions/IAppStateExtensions.cs delete mode 100644 src/Strem.Youtube/Models/YoutubeOAuthAuthorizePayload.cs delete mode 100644 src/Strem.Youtube/Models/YoutubeOAuthQuerystringPayload.cs delete mode 100644 src/Strem.Youtube/Models/YoutubeOAuthTokenPayload.cs delete mode 100644 src/Strem.Youtube/Models/YoutubeOAuthValidationPayload.cs delete mode 100644 src/Strem.Youtube/Plugin/YoutubeIntegrationDescriptor.cs delete mode 100644 src/Strem.Youtube/Plugin/YoutubeModule.cs delete mode 100644 src/Strem.Youtube/Plugin/YoutubePluginSettings.cs delete mode 100644 src/Strem.Youtube/Plugin/YoutubePluginStartup.cs delete mode 100644 src/Strem.Youtube/Services/Client/AccessTokenUserCredential.cs delete mode 100644 src/Strem.Youtube/Services/Client/IObservableYoutubeClient.cs delete mode 100644 src/Strem.Youtube/Services/Client/ObservableYoutubeClient.cs delete mode 100644 src/Strem.Youtube/Services/OAuth/IYoutubeOAuthClient.cs delete mode 100644 src/Strem.Youtube/Services/OAuth/YoutubeOAuthClient.cs delete mode 100644 src/Strem.Youtube/Strem.Youtube.csproj delete mode 100644 src/Strem.Youtube/Types/Scopes.cs delete mode 100644 src/Strem.Youtube/Variables/YoutubeVars.cs delete mode 100644 src/Strem.Youtube/Views/Youtube/OAuthFailed.cshtml delete mode 100644 src/Strem.Youtube/Views/Youtube/OAuthSuccess.cshtml delete mode 100644 src/Strem.Youtube/_Imports.razor diff --git a/src/Strem.Youtube/Components/Integrations/YoutubeIntegrationComponent.razor b/src/Strem.Youtube/Components/Integrations/YoutubeIntegrationComponent.razor deleted file mode 100644 index d089c6c..0000000 --- a/src/Strem.Youtube/Components/Integrations/YoutubeIntegrationComponent.razor +++ /dev/null @@ -1,143 +0,0 @@ -@using System.Reactive.Disposables -@using System.Reactive.Linq -@using Strem.Core.Events.Bus -@using Strem.Core.Extensions -@using Strem.Core.State -@using Strem.Youtube.Events.OAuth -@using Strem.Youtube.Extensions -@using Strem.Youtube.Services.OAuth -@using Strem.Youtube.Variables - -@inject IYoutubeOAuthClient YoutubeOAuthClient -@inject IAppState AppState -@inject IEventBus EventBus - -@implements IDisposable - -
- -
- -
-
- -
-
-
-
- -
- See readme for why we need these and how to get your client id/secret for use here -
- - -
-
- -
-
- @if (IsYoutubeAccountLinked && !HavePermissionsChanged) - { - Disconnect From Youtube - } - else if (IsYoutubeAccountLinked && HavePermissionsChanged) - { - Request New Permissions - } - else - { - Connect To Youtube - } -
-
-
- -
- - - - -@code { - - private CompositeDisposable _subs = new(); - - public string Username { get; set; } - public bool IsYoutubeAccountLinked { get; set; } - public bool HavePermissionsChanged { get; set; } - public string[] CurrentScopes { get; set; } = Array.Empty(); - public string[] NewScopes { get; set; } = Array.Empty(); - - public string ClientId - { - get => AppState.AppVariables.Get(YoutubeVars.ClientId); - set => AppState.AppVariables.Set(YoutubeVars.ClientId, value); - } - - public string ClientSecret - { - get => AppState.AppVariables.Get(YoutubeVars.ClientSecret); - set => AppState.AppVariables.Set(YoutubeVars.ClientSecret, value); - } - - public bool HasClientDetails => !string.IsNullOrEmpty(ClientId) && !string.IsNullOrEmpty(ClientSecret); - - protected override async Task OnInitializedAsync() - { - IsYoutubeAccountLinked = AppState.HasYoutubeAccessToken(); - Username = AppState.AppVariables.Get(YoutubeVars.Username); - - if (IsYoutubeAccountLinked) - { - CurrentScopes = AppState.GetYoutubeScopes(); - NewScopes = CurrentScopes.ToArray(); - Username = AppState.GetYoutubeUsername(); - } - - AppState.AppVariables.OnVariableChanged - .Where(x => x.Key == YoutubeVars.Username) - .Subscribe(x => - { - Username = AppState.GetYoutubeUsername(); - InvokeAsync(StateHasChanged); - }) - .AddTo(_subs); - - EventBus.Receive() - .Subscribe(x => - { - IsYoutubeAccountLinked = true; - InvokeAsync(StateHasChanged); - }) - .AddTo(_subs); - - EventBus.Receive() - .Subscribe(x => - { - IsYoutubeAccountLinked = false; - Username = string.Empty; - InvokeAsync(StateHasChanged); - }) - .AddTo(_subs); - } - - public void ConnectToYoutube() - { - YoutubeOAuthClient.StartAuthorisationProcess(NewScopes); - } - - public void DisconnectFromYoutube() - { - YoutubeOAuthClient.RevokeToken(); - } - - public void RequestNewScopeAccess(string[] newScopes) - { - NewScopes = newScopes; - HavePermissionsChanged = true; - } - - public void Dispose() - { - _subs?.Dispose(); - } -} \ No newline at end of file diff --git a/src/Strem.Youtube/Components/ScopeCollections.cs b/src/Strem.Youtube/Components/ScopeCollections.cs deleted file mode 100644 index 95bfbaa..0000000 --- a/src/Strem.Youtube/Components/ScopeCollections.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Strem.Youtube.Types; - -namespace Strem.Youtube.Components; - -public class ScopeCollections -{ - public static string[] ManageChatScopes = new[] { Scopes.ManageYoutube }; - public static string[] ReadChatScopes = new[] { Scopes.ReadYoutube }; -} \ No newline at end of file diff --git a/src/Strem.Youtube/Components/YoutubeLiveChat.razor b/src/Strem.Youtube/Components/YoutubeLiveChat.razor deleted file mode 100644 index 0f7a6cd..0000000 --- a/src/Strem.Youtube/Components/YoutubeLiveChat.razor +++ /dev/null @@ -1,10 +0,0 @@ -
- -
- -@code { - [Parameter] - public string ChannelId { get; set; } - - public string EmbedUrl => $"https://www.youtube.com/live_chat?v={ChannelId}&embed_domain=localhost"; -} \ No newline at end of file diff --git a/src/Strem.Youtube/Components/YoutubeScopes.razor b/src/Strem.Youtube/Components/YoutubeScopes.razor deleted file mode 100644 index e69a57f..0000000 --- a/src/Strem.Youtube/Components/YoutubeScopes.razor +++ /dev/null @@ -1,54 +0,0 @@ -@using Strem.Core.Types - -
-
-
-
- -
- -
- Chat permissions cover being able to read/write chat messages -
-
-
-
- -@code { - - public ScopeAccess ChatAccess { get; set; } - - [Parameter] - public string[] ExistingScopes { get; set; } = Array.Empty(); - - [Parameter] - public EventCallback OnScopesChanged { get; set; } - - public bool HasScopesFor(string[] requiredScopes) - { - return requiredScopes.All(x => ExistingScopes.Contains(x)); - } - - protected override async Task OnInitializedAsync() - { - if (HasScopesFor(ScopeCollections.ManageChatScopes)){ ChatAccess = ScopeAccess.Full; } - else if(HasScopesFor(ScopeCollections.ReadChatScopes)) { ChatAccess = ScopeAccess.ReadOnly; } - else { ChatAccess = ScopeAccess.None; } - } - - public void RequestScopeChange() - { - var newScopes = new List(); - switch (ChatAccess) - { - case ScopeAccess.Full: - newScopes.AddRange(ScopeCollections.ReadChatScopes); - newScopes.AddRange(ScopeCollections.ManageChatScopes); - break; - case ScopeAccess.ReadOnly: - newScopes.AddRange(ScopeCollections.ReadChatScopes); - break; - } - OnScopesChanged.InvokeAsync(newScopes.ToArray()); - } -} \ No newline at end of file diff --git a/src/Strem.Youtube/Controllers/YoutubeController.cs b/src/Strem.Youtube/Controllers/YoutubeController.cs deleted file mode 100644 index 854fadd..0000000 --- a/src/Strem.Youtube/Controllers/YoutubeController.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Strem.Core.Events; -using Strem.Core.Extensions; -using Strem.Core.State; -using Strem.Core.Variables; -using Strem.Infrastructure.Extensions; -using Strem.Youtube.Events.OAuth; -using Strem.Youtube.Models; -using Strem.Youtube.Services.OAuth; -using Strem.Youtube.Variables; - -namespace Strem.Youtube.Controllers; - -[ApiController] -[Route("api/youtube")] -public class YoutubeController : Controller -{ - public IAppState AppState { get; } - public ILogger Logger { get; } - public IYoutubeOAuthClient OAuthClient { get; } - - public YoutubeController() - { - AppState = this.GetService(); - OAuthClient = this.GetService(); - Logger = this.GetLogger(); - } - - [HttpGet] - public IActionResult Index() - { return Ok("Youtube OAuth Works Fine"); } - - [HttpGet] - [Route("oauth")] - public async Task OAuthYoutubeAuthorizeCallback([FromQuery]YoutubeOAuthAuthorizePayload? payload) - { - if (!string.IsNullOrEmpty(payload?.Error)) - { - var errorMessage = $"[Youtube OAuth]: Error Approving OAuth: {payload.Error} | {payload.ErrorDescription}"; - Logger.Error(errorMessage); - return View("OAuthFailed", errorMessage); - } - - var existingState = AppState.TransientVariables.Get(CommonVariables.OAuthState, YoutubeVars.Context); - if (payload?.State != existingState) - { - var errorMessage = $"[Youtube OAuth]: Client callback issue, OAuth state does not match request state:"; - Logger.Error(errorMessage); - return View("OAuthFailed", errorMessage); - } - - Logger.Information("[Youtube OAuth]: Got callback, handling code exchange"); - var wasSuccessful = await OAuthClient.GetToken(payload.Code); - - var logText = wasSuccessful ? "succeeded" : "failed"; - Logger.Information($"[Youtube OAuth]: Code exchange {logText}"); - return !wasSuccessful - ? View("OAuthFailed", "Unable to retrieve token from Youtube api, please try again later") - : View("OAuthSuccess"); - } -} \ No newline at end of file diff --git a/src/Strem.Youtube/Events/OAuth/YoutubeOAuthRevokedEvent.cs b/src/Strem.Youtube/Events/OAuth/YoutubeOAuthRevokedEvent.cs deleted file mode 100644 index 7e1d17c..0000000 --- a/src/Strem.Youtube/Events/OAuth/YoutubeOAuthRevokedEvent.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Strem.Youtube.Events.OAuth; - -public class YoutubeOAuthRevokedEvent -{} \ No newline at end of file diff --git a/src/Strem.Youtube/Events/OAuth/YoutubeOAuthSuccessEvent.cs b/src/Strem.Youtube/Events/OAuth/YoutubeOAuthSuccessEvent.cs deleted file mode 100644 index edb999f..0000000 --- a/src/Strem.Youtube/Events/OAuth/YoutubeOAuthSuccessEvent.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Strem.Youtube.Events.OAuth; - -public class YoutubeOAuthSuccessEvent -{} \ No newline at end of file diff --git a/src/Strem.Youtube/Events/OAuth/YoutubeOAuthTokenExpiredEvent.cs b/src/Strem.Youtube/Events/OAuth/YoutubeOAuthTokenExpiredEvent.cs deleted file mode 100644 index 039701d..0000000 --- a/src/Strem.Youtube/Events/OAuth/YoutubeOAuthTokenExpiredEvent.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Strem.Youtube.Events.OAuth; - -public class YoutubeOAuthTokenExpiredEvent -{} \ No newline at end of file diff --git a/src/Strem.Youtube/Extensions/IAppStateExtensions.cs b/src/Strem.Youtube/Extensions/IAppStateExtensions.cs deleted file mode 100644 index d09cfac..0000000 --- a/src/Strem.Youtube/Extensions/IAppStateExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Strem.Core.State; -using Strem.Youtube.Variables; - -namespace Strem.Youtube.Extensions; - -public static class IAppStateExtensions -{ - public static bool HasYoutubeAccessToken(this IAppState state) => state.AppVariables.Has(YoutubeVars.OAuthToken); - public static string GetYoutubeAccessToken(this IAppState state) => state.AppVariables.Get(YoutubeVars.OAuthToken); - - public static string GetYoutubeUsername(this IAppState state) => state.AppVariables.Get(YoutubeVars.Username); - public static string GetYoutubeChannelId(this IAppState state) => state.AppVariables.Get(YoutubeVars.ChannelId); - - public static bool HasYoutubeScope(this IAppState state, string scope) => state.AppVariables.Get(YoutubeVars.OAuthScopes).Contains(scope, StringComparison.OrdinalIgnoreCase); - public static string[] GetYoutubeScopes(this IAppState state) => state.AppVariables.Get(YoutubeVars.OAuthScopes).Split(","); - - -} \ No newline at end of file diff --git a/src/Strem.Youtube/Models/YoutubeOAuthAuthorizePayload.cs b/src/Strem.Youtube/Models/YoutubeOAuthAuthorizePayload.cs deleted file mode 100644 index 9500522..0000000 --- a/src/Strem.Youtube/Models/YoutubeOAuthAuthorizePayload.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Microsoft.AspNetCore.Mvc; - -namespace Strem.Youtube.Models; - -public class YoutubeOAuthAuthorizePayload -{ - public string? Code { get; set; } - public string? Error { get; set; } - [BindProperty(Name = "error_description")] - public string? ErrorDescription { get; set; } - public string? State { get; set; } -} \ No newline at end of file diff --git a/src/Strem.Youtube/Models/YoutubeOAuthQuerystringPayload.cs b/src/Strem.Youtube/Models/YoutubeOAuthQuerystringPayload.cs deleted file mode 100644 index 327eaa7..0000000 --- a/src/Strem.Youtube/Models/YoutubeOAuthQuerystringPayload.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Microsoft.AspNetCore.Mvc; - -namespace Strem.Youtube.Models; - -public class YoutubeOAuthQuerystringPayload -{ - public string? Code { get; set; } - public string? Error { get; set; } - [BindProperty(Name = "error_description")] - public string? ErrorDescription { get; set; } - public string? State { get; set; } -} \ No newline at end of file diff --git a/src/Strem.Youtube/Models/YoutubeOAuthTokenPayload.cs b/src/Strem.Youtube/Models/YoutubeOAuthTokenPayload.cs deleted file mode 100644 index 272795c..0000000 --- a/src/Strem.Youtube/Models/YoutubeOAuthTokenPayload.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Newtonsoft.Json; - -namespace Strem.Youtube.Models; - -public class YoutubeOAuthTokenPayload -{ - [JsonProperty("refresh_token")] - public string RefreshToken { get; set; } - [JsonProperty("access_token")] - public string AccessToken { get; set; } - [JsonProperty("token_type")] - public string TokenType { get; set; } - [JsonProperty("expires_in")] - public int ExpiresIn { get; set; } - [JsonProperty("scope")] - public string Scope { get; set; } -} \ No newline at end of file diff --git a/src/Strem.Youtube/Models/YoutubeOAuthValidationPayload.cs b/src/Strem.Youtube/Models/YoutubeOAuthValidationPayload.cs deleted file mode 100644 index f9868b7..0000000 --- a/src/Strem.Youtube/Models/YoutubeOAuthValidationPayload.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Newtonsoft.Json; - -namespace Strem.Youtube.Models; - -public class YoutubeOAuthValidationPayload -{ - [JsonProperty("client_id")] - public string ClientId { get; set; } - public string Login { get; set; } - public string[] Scopes { get; set; } - [JsonProperty("expires_in")] - public int ExpiresIn { get; set; } -} \ No newline at end of file diff --git a/src/Strem.Youtube/Plugin/YoutubeIntegrationDescriptor.cs b/src/Strem.Youtube/Plugin/YoutubeIntegrationDescriptor.cs deleted file mode 100644 index 9a73f8c..0000000 --- a/src/Strem.Youtube/Plugin/YoutubeIntegrationDescriptor.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Strem.Core.Services.Registries.Integrations; -using Strem.Core.Variables; -using Strem.Youtube.Components.Integrations; - -namespace Strem.Youtube.Plugin; - -public class YoutubeIntegrationDescriptor : IIntegrationDescriptor -{ - public string Title => "Youtube Integration"; - public string Code => "youtube-integration"; - - public VariableDescriptor[] VariableOutputs { get; } = Array.Empty(); - - public Type ComponentType { get; } = typeof(YoutubeIntegrationComponent); -} \ No newline at end of file diff --git a/src/Strem.Youtube/Plugin/YoutubeModule.cs b/src/Strem.Youtube/Plugin/YoutubeModule.cs deleted file mode 100644 index 2a9aac8..0000000 --- a/src/Strem.Youtube/Plugin/YoutubeModule.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Google.Apis.PeopleService.v1; -using Google.Apis.Services; -using Google.Apis.YouTube.v3; -using Strem.Core.Plugins; -using Strem.Core.Services.Registries.Integrations; -using Strem.Flows.Extensions; -using Strem.Infrastructure.Services.Api; -using Strem.Youtube.Services.Client; -using Strem.Youtube.Services.OAuth; - -namespace Strem.Youtube.Plugin; - -public class YoutubeModule : IRequiresApiHostingModule -{ - public void Setup(IServiceCollection services) - { - // Plugin - services.AddSingleton(); - - // OAuth - services.AddSingleton(); - - // General - services.AddSingleton(); - services.AddSingleton(CreateYoutubeClient); - services.AddSingleton(CreatePeopleService); - services.AddSingleton(); - - // Components - var thisAssembly = GetType().Assembly; - services.RegisterAllTasksAndComponentsIn(thisAssembly); - services.RegisterAllTriggersAndComponentsIn(thisAssembly); - - // Integration Components - services.AddSingleton(); - } - - public YouTubeService CreateYoutubeClient(IServiceProvider services) - { - var credentialHandler = services.GetService(); - return new YouTubeService(new BaseClientService.Initializer(){ HttpClientInitializer = credentialHandler }); - } - - public PeopleServiceService CreatePeopleService(IServiceProvider services) - { - var credentialHandler = services.GetService(); - return new PeopleServiceService(new BaseClientService.Initializer() { HttpClientInitializer = credentialHandler }); - } -} \ No newline at end of file diff --git a/src/Strem.Youtube/Plugin/YoutubePluginSettings.cs b/src/Strem.Youtube/Plugin/YoutubePluginSettings.cs deleted file mode 100644 index a65e5a1..0000000 --- a/src/Strem.Youtube/Plugin/YoutubePluginSettings.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Strem.Youtube.Plugin; - -public class YoutubePluginSettings -{ - // Local Config - public static readonly int RevalidatePeriodInMins = 60; - public static readonly int ChatReconnectInMins = 1; - public static readonly int RefreshChannelPeriodInMins = 5; -} \ No newline at end of file diff --git a/src/Strem.Youtube/Plugin/YoutubePluginStartup.cs b/src/Strem.Youtube/Plugin/YoutubePluginStartup.cs deleted file mode 100644 index e6f4447..0000000 --- a/src/Strem.Youtube/Plugin/YoutubePluginStartup.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System.Reactive.Disposables; -using System.Reactive.Linq; -using Google.Apis.PeopleService.v1.Data; -using Strem.Core.Events.Bus; -using Strem.Core.Extensions; -using Strem.Core.Plugins; -using Strem.Core.State; -using Strem.Youtube.Events.OAuth; -using Strem.Youtube.Extensions; -using Strem.Youtube.Services.Client; -using Strem.Youtube.Services.OAuth; -using Strem.Youtube.Variables; - -namespace Strem.Youtube.Plugin; - -public class YoutubePluginStartup : IPluginStartup, IDisposable -{ - private CompositeDisposable _subs = new(); - - public IYoutubeOAuthClient YoutubeOAuthClient { get; } - public IObservableYoutubeClient YoutubeClient { get; } - - public IEventBus EventBus { get; } - public IAppState AppState { get; } - public ILogger Logger { get; } - - public string[] RequiredConfigurationKeys { get; } = Array.Empty(); - - public YoutubePluginStartup(IEventBus eventBus, IAppState appState, ILogger logger, IObservableYoutubeClient youtubeClient, IYoutubeOAuthClient youtubeOAuthClient) - { - YoutubeOAuthClient = youtubeOAuthClient; - EventBus = eventBus; - AppState = appState; - Logger = logger; - YoutubeClient = youtubeClient; - } - - public Task SetupPlugin() => Task.CompletedTask; - - public async Task StartPlugin() - { - Observable.Timer(TimeSpan.FromMinutes(YoutubePluginSettings.RevalidatePeriodInMins)) - .Subscribe(x => VerifyToken()) - .AddTo(_subs); - - Observable.Timer(TimeSpan.FromMinutes(YoutubePluginSettings.RefreshChannelPeriodInMins)) - .Subscribe(x => RefreshStreamDetails()) - .AddTo(_subs); - - EventBus.Receive() - .Subscribe(_ => CacheUserData()) - .AddTo(_subs); - - try - { - await VerifyToken(); - await CacheUserData(); - } - catch (Exception e) - { Logger.Warning($"Error setting up Youtube Plugin: {e.Message}"); } - } - - private async Task CacheUserData() - { - if (!AppState.HasYoutubeAccessToken()) { return; } - - try - { - var currentUser = await YoutubeClient.GetCurrentUser(); - var name = currentUser.Names.FirstOrDefault(new Name() { DisplayName = "Unknown User - No Names Listed"}).DisplayName; - AppState.TransientVariables.Set(YoutubeVars.ChannelId, currentUser.ResourceName); - AppState.TransientVariables.Set(YoutubeVars.Username, name); - AppState.AppVariables.Set(YoutubeVars.Username, name); - } - catch (Exception e) - { - Logger.Warning($"Unable to get user details from google: {e.Message}"); - AppState.TransientVariables.Set(YoutubeVars.ChannelId, string.Empty); - AppState.TransientVariables.Set(YoutubeVars.Username, "Unknown User - Missing Permissions"); - AppState.AppVariables.Set(YoutubeVars.Username, "Unknown User - Missing Permissions"); - } - } - - public async Task VerifyToken() - { - Logger.Information("Revalidating Youtube Access Token"); - - if (AppState.HasYoutubeAccessToken()) - { await YoutubeOAuthClient.RefreshToken(); } - } - - public async Task RefreshStreamDetails() - { - Logger.Information("Updating Youtube Channel Info"); - try - { - var usersChannels = await YoutubeClient.GetCurrentUsersChannels(); - foreach (var channel in usersChannels) - { - Logger.Information($"User Has Channel: [{channel.Id} | {channel.Snippet.Title}]"); - } - } - catch (Exception e) - { - Logger.Error($"YT CHANNEL ERROR {e.Message}"); - } - } - - public void Dispose() - { _subs?.Dispose(); } -} \ No newline at end of file diff --git a/src/Strem.Youtube/Services/Client/AccessTokenUserCredential.cs b/src/Strem.Youtube/Services/Client/AccessTokenUserCredential.cs deleted file mode 100644 index 50f8a50..0000000 --- a/src/Strem.Youtube/Services/Client/AccessTokenUserCredential.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Net.Http.Headers; -using Google.Apis.Http; -using Strem.Core.State; -using Strem.Youtube.Extensions; - -namespace Strem.Youtube.Services.Client; - -public class AccessTokenUserCredential : IHttpExecuteInterceptor, IConfigurableHttpClientInitializer -{ - public IAppState AppState { get; } - - public AccessTokenUserCredential(IAppState appState) - { - AppState = appState; - } - - public void Initialize(ConfigurableHttpClient httpClient) - { - httpClient.MessageHandler.AddExecuteInterceptor(this); - } - - public async Task InterceptAsync(HttpRequestMessage request, CancellationToken cancellationToken) - { - var accessToken = string.Empty; - if (AppState.HasYoutubeAccessToken()) - { accessToken = AppState.GetYoutubeAccessToken(); } - - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); - } -} \ No newline at end of file diff --git a/src/Strem.Youtube/Services/Client/IObservableYoutubeClient.cs b/src/Strem.Youtube/Services/Client/IObservableYoutubeClient.cs deleted file mode 100644 index 02bcaca..0000000 --- a/src/Strem.Youtube/Services/Client/IObservableYoutubeClient.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Google.Apis.PeopleService.v1; -using Google.Apis.PeopleService.v1.Data; -using Google.Apis.YouTube.v3; -using Google.Apis.YouTube.v3.Data; - -namespace Strem.Youtube.Services.Client; - -public interface IObservableYoutubeClient -{ - YouTubeService YoutubeApiClient { get; } - PeopleServiceService PeopleApiService { get; } - Task GetCurrentUser(); - Task> GetCurrentUsersChannels(); -} \ No newline at end of file diff --git a/src/Strem.Youtube/Services/Client/ObservableYoutubeClient.cs b/src/Strem.Youtube/Services/Client/ObservableYoutubeClient.cs deleted file mode 100644 index f1bf054..0000000 --- a/src/Strem.Youtube/Services/Client/ObservableYoutubeClient.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Google.Apis.PeopleService.v1; -using Google.Apis.PeopleService.v1.Data; -using Google.Apis.YouTube.v3; -using Google.Apis.YouTube.v3.Data; - -namespace Strem.Youtube.Services.Client; - -public class ObservableYoutubeClient : IObservableYoutubeClient -{ - public YouTubeService YoutubeApiClient { get; } - public PeopleServiceService PeopleApiService { get; } - - public DateTime LastChatUpdateTime { get; set; } - - /// Occurs when [on channel state changed]. - public IObservable OnChannelStateChanged { get; private set; } - - public ObservableYoutubeClient(YouTubeService youtubeClient, PeopleServiceService peopleClient) - { - YoutubeApiClient = youtubeClient; - PeopleApiService = peopleClient; - } - - public void SetupObservables() - { - //YoutubeApiClient.LiveStreams. - } - - public Task GetCurrentUser() - { - var personRequest = PeopleApiService.People.Get("people/me"); - personRequest.PersonFields = "names"; - return personRequest.ExecuteAsync(); - } - - public async Task> GetCurrentUsersChannels() - { - var channelRequest = YoutubeApiClient.Channels.List("id, snippet"); - channelRequest.Mine = true; - var result = await channelRequest.ExecuteAsync(); - return result.Items; - } - - public void StartListeningForChatMessagesOn(string liveChatId) - { - LastChatUpdateTime = new DateTime(); - var request = YoutubeApiClient.LiveChatMessages.List(liveChatId, "id, snippet"); - var a = request.Execute(); - - } -} \ No newline at end of file diff --git a/src/Strem.Youtube/Services/OAuth/IYoutubeOAuthClient.cs b/src/Strem.Youtube/Services/OAuth/IYoutubeOAuthClient.cs deleted file mode 100644 index ba7b7e8..0000000 --- a/src/Strem.Youtube/Services/OAuth/IYoutubeOAuthClient.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Strem.Youtube.Models; - -namespace Strem.Youtube.Services.OAuth; - -public interface IYoutubeOAuthClient -{ - void StartAuthorisationProcess(string[] requiredScopes); - Task GetToken(string code); - Task RefreshToken(); - Task RevokeToken(); -} \ No newline at end of file diff --git a/src/Strem.Youtube/Services/OAuth/YoutubeOAuthClient.cs b/src/Strem.Youtube/Services/OAuth/YoutubeOAuthClient.cs deleted file mode 100644 index b5e8614..0000000 --- a/src/Strem.Youtube/Services/OAuth/YoutubeOAuthClient.cs +++ /dev/null @@ -1,200 +0,0 @@ -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using RestSharp; -using Strem.Core.Events.Bus; -using Strem.Core.Extensions; -using Strem.Core.Services.Browsers.Web; -using Strem.Core.Services.Utils; -using Strem.Core.State; -using Strem.Core.Variables; -using Strem.Infrastructure.Services.Api; -using Strem.Youtube.Events.OAuth; -using Strem.Youtube.Extensions; -using Strem.Youtube.Models; -using Strem.Youtube.Types; -using Strem.Youtube.Variables; - -namespace Strem.Youtube.Services.OAuth; - -public class YoutubeOAuthClient : IYoutubeOAuthClient -{ - public static readonly string OAuthCallbackUrl = $"http://localhost:{InternalWebHostConfiguration.ApiHostPort}/api/youtube/oauth"; - - public static readonly string ApiUrl = "https://accounts.google.com/o/oauth2"; - public static readonly string AuthorizeEndpoint = "v2/auth"; - public static readonly string TokenEndpoint = "token"; - public static readonly string RevokeEndpoint = "revoke"; - - public IWebBrowser WebBrowser { get; } - public IAppState AppState { get; } - public IApplicationConfig AppConfig { get; } - public IEventBus EventBus { get; } - public IRandomizer Randomizer { get; } - public ILogger Logger { get; } - - public YoutubeOAuthClient(IWebBrowser webBrowser, IAppState appState, IRandomizer randomizer, IEventBus eventBus, ILogger logger, IApplicationConfig appConfig) - { - WebBrowser = webBrowser; - AppState = appState; - Randomizer = randomizer; - EventBus = eventBus; - Logger = logger; - AppConfig = appConfig; - } - - public void StartAuthorisationProcess(string[] requiredScopes) - { - Logger.Information("Starting Youtube PKCE OAuth Process"); - - var randomState = Randomizer.RandomString(); - var challengeCode = Randomizer.RandomString(); - AppState.TransientVariables.Set(CommonVariables.OAuthState, YoutubeVars.Context, randomState); - AppState.TransientVariables.Set(CommonVariables.OAuthChallengeCode, YoutubeVars.Context, challengeCode); - - var clientId = AppState.AppVariables.Get(YoutubeVars.ClientId); - - var completeScopes = requiredScopes.ToList(); - if(!completeScopes.Contains(Scopes.Profile)) - { completeScopes.Add(Scopes.Profile); } - - var scopeQueryData = Uri.EscapeDataString(string.Join(" ", completeScopes)); - var challengeData = $"code_challenge={challengeCode}&code_challenge_method=plain"; - var queryData = $"client_id={clientId}&redirect_uri={OAuthCallbackUrl}&response_type=code&scope={scopeQueryData}&state={randomState}&{challengeData}"; - var completeUrl = $"{ApiUrl}/{AuthorizeEndpoint}?{queryData}"; - WebBrowser.LoadUrl(completeUrl); - } - - public async Task GetToken(string code) - { - var restClient = new RestClient(ApiUrl); - var restRequest = new RestRequest(TokenEndpoint, Method.Post); - restRequest.AddHeader("Content-Type", "application/x-www-form-urlencoded"); - - var clientId = AppState.AppVariables.Get(YoutubeVars.ClientId); - var clientSecret = AppState.AppVariables.Get(YoutubeVars.ClientSecret); - - var clientContent = $"client_id={clientId}&client_secret={clientSecret}&redirect_uri={OAuthCallbackUrl}"; - var challengeCode = AppState.TransientVariables.Get(CommonVariables.OAuthChallengeCode, YoutubeVars.Context); - var codeContent = $"grant_type=authorization_code&code={code}&code_verifier={challengeCode}"; - var completeBody = $"{clientContent}&{codeContent}"; - restRequest.AddStringBody(completeBody, DataFormat.None); - - var response = await restClient.ExecuteAsync(restRequest); - if (!response.IsSuccessful) - { - Logger.Error($"Validation Error: {response.Content ?? "unknown error validating"}"); - ClearTokenState(); - return false; - } - - var payload = JsonConvert.DeserializeObject(response.Content); - if (string.IsNullOrEmpty(payload?.AccessToken)) - { - Logger.Error($"Payload Validation Error: {response.Content ?? "unknown error validating"}"); - ClearTokenState(); - return false; - } - - RefreshTokenState(payload); - EventBus.PublishAsync(new YoutubeOAuthSuccessEvent()); - return true; - } - - public async Task RefreshToken() - { - Logger.Information("Refreshing Youtube Token"); - - var refreshToken = AppState.AppVariables.Get(YoutubeVars.OAuthRefreshToken); - if (string.IsNullOrEmpty(refreshToken)) - { return false; } - - var restClient = new RestClient(ApiUrl); - var restRequest = new RestRequest(TokenEndpoint, Method.Post); - restRequest.AddHeader("Content-Type", "application/x-www-form-urlencoded"); - - var clientId = AppState.AppVariables.Get(YoutubeVars.ClientId); - - var clientContent = $"client_id={clientId}"; - var codeContent = $"grant_type=refresh_token&refresh_token={refreshToken}"; - var totalContent = $"{clientContent}&{codeContent}"; - restRequest.AddStringBody(totalContent, DataFormat.None); - - var response = await restClient.ExecuteAsync(restRequest); - if (!response.IsSuccessful) - { - Logger.Error($"Validation Error: {response.Content ?? "unknown error validating"}"); - ClearTokenState(); - return false; - } - - var payload = JsonConvert.DeserializeObject(response.Content); - if (string.IsNullOrEmpty(payload?.AccessToken)) - { - Logger.Error($"Payload Validation Error: {response.Content ?? "unknown error validating"}"); - ClearTokenState(); - return false; - } - - RefreshTokenState(payload); - EventBus.PublishAsync(new YoutubeOAuthSuccessEvent()); - return true; - } - - public async Task RevokeToken() - { - Logger.Information("Revoking Twitter Token"); - - var accessToken = AttemptGetAccessToken(); - if (accessToken == null) { return false; } - - var clientId = AppState.AppVariables.Get(YoutubeVars.ClientId); - - var restClient = new RestClient(ApiUrl); - var restRequest = new RestRequest(RevokeEndpoint, Method.Post); - restRequest.AddHeader("Content-Type", "application/x-www-form-urlencoded"); - restRequest.AddStringBody($"token={accessToken}", DataFormat.None); - - var response = await restClient.ExecuteAsync(restRequest); - if (!response.IsSuccessful) - { - Logger.Error($"Revoke Error: {response.Content ?? "unknown error revoking"}"); - ClearTokenState(); - return false; - } - - EventBus.PublishAsync(new YoutubeOAuthRevokedEvent()); - ClearTokenState(); - return true; - } - - public string AttemptGetAccessToken() - { - if (AppState.HasYoutubeAccessToken()) - { return AppState.GetYoutubeAccessToken(); } - - Logger.Error("Cannot find OAuth Token In Vars for request to Youtube OAuth API"); - return null; - } - - public void RefreshTokenState(YoutubeOAuthTokenPayload payload) - { - AppState.AppVariables.Set(YoutubeVars.OAuthToken, payload.AccessToken); - AppState.AppVariables.Set(YoutubeVars.OAuthRefreshToken, payload.RefreshToken); - - var scopes = payload.Scope.Replace(" ", ","); - AppState.AppVariables.Set(YoutubeVars.OAuthScopes, scopes); - - var actualExpiry = DateTime.Now.AddSeconds(payload.ExpiresIn); - AppState.AppVariables.Set(YoutubeVars.TokenExpiry, actualExpiry.ToString("u")); - } - - public void ClearTokenState() - { - AppState.AppVariables.Delete(YoutubeVars.Username); - AppState.AppVariables.Delete(YoutubeVars.TokenExpiry); - AppState.AppVariables.Delete(YoutubeVars.OAuthScopes); - AppState.AppVariables.Delete(YoutubeVars.OAuthToken); - AppState.AppVariables.Delete(YoutubeVars.OAuthRefreshToken); - AppState.AppVariables.Delete(CommonVariables.OAuthChallengeCode, YoutubeVars.Context); - } -} \ No newline at end of file diff --git a/src/Strem.Youtube/Strem.Youtube.csproj b/src/Strem.Youtube/Strem.Youtube.csproj deleted file mode 100644 index 16bff0c..0000000 --- a/src/Strem.Youtube/Strem.Youtube.csproj +++ /dev/null @@ -1,34 +0,0 @@ - - - - net8.0 - enable - enable - Library - 0.0.0 - true - 12 - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Strem.Youtube/Types/Scopes.cs b/src/Strem.Youtube/Types/Scopes.cs deleted file mode 100644 index d828b84..0000000 --- a/src/Strem.Youtube/Types/Scopes.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Strem.Youtube.Types; - -public class Scopes -{ - public static readonly string Profile = "https://www.googleapis.com/auth/userinfo.profile"; - public static readonly string ManageYoutube = "https://www.googleapis.com/auth/youtube"; - public static readonly string ReadYoutube = "https://www.googleapis.com/auth/youtube.readonly"; -} \ No newline at end of file diff --git a/src/Strem.Youtube/Variables/YoutubeVars.cs b/src/Strem.Youtube/Variables/YoutubeVars.cs deleted file mode 100644 index 155c327..0000000 --- a/src/Strem.Youtube/Variables/YoutubeVars.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Strem.Core.Variables; - -namespace Strem.Youtube.Variables; - -public class YoutubeVars -{ - // Generic - public static readonly string Context = "youtube"; - - // OAuth (app) - public static readonly VariableEntry OAuthToken = new(CommonVariables.OAuthAccessToken, Context); - public static readonly VariableEntry OAuthRefreshToken = new(CommonVariables.OAuthRefreshToken, Context); - public static readonly VariableEntry TokenExpiry = new("token-expiry", Context); - public static readonly VariableEntry OAuthScopes = new("oauth-scopes", Context); - - // App - public static readonly VariableEntry ClientId = new("client-id", Context); - public static readonly VariableEntry ClientSecret = new("client-secret", Context); - - // User (app) - public static readonly VariableEntry ChannelId = new("channelId", Context); - public static readonly VariableEntry Username = new("username", Context); -} \ No newline at end of file diff --git a/src/Strem.Youtube/Views/Youtube/OAuthFailed.cshtml b/src/Strem.Youtube/Views/Youtube/OAuthFailed.cshtml deleted file mode 100644 index de945d5..0000000 --- a/src/Strem.Youtube/Views/Youtube/OAuthFailed.cshtml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Youtube Said NO - - - - -
-
-
-
-

- - - - - - Youtube Error Authorizing -

-

- @Model -

-

- Please close window and try in app again -

-
-
-
-
- - \ No newline at end of file diff --git a/src/Strem.Youtube/Views/Youtube/OAuthSuccess.cshtml b/src/Strem.Youtube/Views/Youtube/OAuthSuccess.cshtml deleted file mode 100644 index bb08894..0000000 --- a/src/Strem.Youtube/Views/Youtube/OAuthSuccess.cshtml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - Youtube Is Calling - - - - -
-
-
-
-

- - - - - - Youtube Is A Go Go! -

-

You can now close this page

-
-
-
-
- - \ No newline at end of file diff --git a/src/Strem.Youtube/_Imports.razor b/src/Strem.Youtube/_Imports.razor deleted file mode 100644 index 904230f..0000000 --- a/src/Strem.Youtube/_Imports.razor +++ /dev/null @@ -1,10 +0,0 @@ -@using System.Net.Http -@using System.Net.Http.Json -@using Microsoft.AspNetCore.Components.Forms -@using Microsoft.AspNetCore.Components.Routing -@using Microsoft.AspNetCore.Components.Web -@using Strem.Core.Components; -@using Strem.Core.Components.Elements; -@using Strem.Core.Components.Elements.Inputs; -@using Strem.Flows.Components.Tasks; -@using Strem.Flows.Components.Triggers; \ No newline at end of file diff --git a/src/Strem.sln b/src/Strem.sln index 3651290..db73c41 100644 --- a/src/Strem.sln +++ b/src/Strem.sln @@ -42,8 +42,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Strem.Platforms.Windows", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Strem.OBS", "Strem.OBS\Strem.OBS.csproj", "{978C7A45-2EAD-4B84-B2CC-022D23863B8B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Strem.Youtube", "Strem.Youtube\Strem.Youtube.csproj", "{BA087273-0079-49E8-8322-B798C90B3E0F}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -110,10 +108,6 @@ Global {978C7A45-2EAD-4B84-B2CC-022D23863B8B}.Debug|Any CPU.Build.0 = Debug|Any CPU {978C7A45-2EAD-4B84-B2CC-022D23863B8B}.Release|Any CPU.ActiveCfg = Release|Any CPU {978C7A45-2EAD-4B84-B2CC-022D23863B8B}.Release|Any CPU.Build.0 = Release|Any CPU - {BA087273-0079-49E8-8322-B798C90B3E0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BA087273-0079-49E8-8322-B798C90B3E0F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BA087273-0079-49E8-8322-B798C90B3E0F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BA087273-0079-49E8-8322-B798C90B3E0F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {D123423B-E3F3-4DEB-B0EF-4D5DE77F223F} = {2CEA373A-AD7C-4D1C-ABB9-48FF5F1A125F} @@ -131,6 +125,5 @@ Global {21960B18-2FC7-4120-9005-DF8EEB9976D2} = {ED8F5401-3000-436F-B463-5DD983410E25} {56F47A4F-4952-4E0E-B7F2-6C22CFB55F80} = {399CB67E-F2C3-407D-9321-391E05D585E4} {978C7A45-2EAD-4B84-B2CC-022D23863B8B} = {51C153FC-60C7-4958-AEFE-419EFD061794} - {BA087273-0079-49E8-8322-B798C90B3E0F} = {51C153FC-60C7-4958-AEFE-419EFD061794} EndGlobalSection EndGlobal diff --git a/src/Strem/Application/PluginHandler.cs b/src/Strem/Application/PluginHandler.cs index 42bc0fc..1583b4c 100644 --- a/src/Strem/Application/PluginHandler.cs +++ b/src/Strem/Application/PluginHandler.cs @@ -16,7 +16,6 @@ using Strem.Twitch.Plugin; using Strem.OBS.Plugin; using Strem.StreamElements.Plugin; -using Strem.Youtube.Plugin; namespace Strem.Application; @@ -52,7 +51,6 @@ public void PreLoadLocalPlugins() _ = typeof(PortalsModule).Assembly; _ = typeof(TodoModule).Assembly; _ = typeof(TwitchModule).Assembly; - _ = typeof(YoutubeModule).Assembly; _ = typeof(OBSModule).Assembly; _ = typeof(StreamElementsModule).Assembly; } diff --git a/src/Strem/Strem.csproj b/src/Strem/Strem.csproj index c487a63..d74ccdc 100644 --- a/src/Strem/Strem.csproj +++ b/src/Strem/Strem.csproj @@ -34,7 +34,6 @@ - diff --git a/src/Strem/wwwroot/css/app-styles.less b/src/Strem/wwwroot/css/app-styles.less index 679279b..c299fc8 100644 --- a/src/Strem/wwwroot/css/app-styles.less +++ b/src/Strem/wwwroot/css/app-styles.less @@ -388,7 +388,6 @@ li.drag-source @twitch-color: #6441a5; @stream-elements-color: #333343; @obs-color: #4a4a4a; -@youtube-color: #FF0000; .integration-menu { @@ -397,7 +396,6 @@ li.drag-source a.stream-elements-integration { border-color: @stream-elements-color; } a.twitch-integration { border-color: @twitch-color; } a.obs-integration { border-color: @obs-color; } - a.youtube-integration { border-color: @youtube-color; } } .integration-components .accordion @@ -411,5 +409,4 @@ li.drag-source &>a.twitch-integration { background-color: @twitch-color; } &>a.stream-elements-integration { background-color: @stream-elements-color; } &>a.obs-integration-v4, &>a.obs-integration { background-color: @obs-color; } - &>a.youtube-integration-v4, &>a.youtube-integration { background-color: @youtube-color; } } \ No newline at end of file