diff --git a/.gitignore b/.gitignore index 60b1383..4e35d3d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,84 +1,41 @@ -# Testing Directory -/testing/ +/testing +SpotifyABClient/*.user + +# Credits @ //github.com/aspnetboilerplate/aspnet-core-template/blob/master/.gitignore + +# Build Folders (you can keep bin if you'd like, to store dlls and pdbs) +[Bb]in/ +[Oo]bj/ + +# Logs +Logs/ + +# Generated files +project.lock.json +.vs/ + +# mstest test results +TestResults -# C# builds and packages ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.suo *.user -*.userosscache *.sln.docstates -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Tools pulled down during build -.tools/ -.dotnet/ -.packages/ - # Build results [Dd]ebug/ -[Dd]ebugPublic/ [Rr]elease/ -[Rr]eleases/ x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio cache/options directory -.vs/ -.vscode/ - -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ -.dotnet/ - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio *_i.c *_p.c -*_i.h *.ilk *.meta *.obj -*.iobj *.pch *.pdb -*.ipdb *.pgc *.pgd *.rsp @@ -87,87 +44,35 @@ StyleCopReport.xml *.tli *.tlh *.tmp -*.tmp_proj *.log *.vspscc *.vssscc .builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb -*.opendb *.opensdf *.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# Visual Studio Code -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json +_ReSharper* # NCrunch -_NCrunch_* +*.ncrunch* .*crunch*.local.xml -nCrunchTemp_* -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ +# Installshield output folder +[Ee]xpress # DocProject is a documentation generator add-in DocProject/buildhelp/ @@ -180,212 +85,36 @@ DocProject/Help/Html2 DocProject/Help/html # Click-Once directory -publish/ +publish # Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj +*.Publish.xml -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ +# NuGet Packages Directory +packages -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ +# Windows Azure Build Output +csx *.build.csdef -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files +# Windows Store app package directory AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Windows image file caches -**/Thumbs.db # Others -ClientBin/ +[Bb]in +[Oo]bj +sql +[Tt]est[Rr]esult* +*.Cache +ClientBin +[Ss]tyle[Cc]op.* ~$* -*~ *.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ +Generated_Code #added for RIA/Silverlight projects -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# JetBrains Rider -.idea/ -*.sln.iml - -# CodeRush -.cr/ - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -### OSX ### - -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -# Ignore "InteropTests/NativeTests/out" -InteropTests/NativeTests/out -/src/System.Windows.Forms/src/comctl32.dll -*.received.* - -# Normally do not want to pick up changes in the scratch project, this will ignore files that aren't already tracked. -# 'git update-index --assume-unchanged ' will allow ignoring changes for tracked files. -**/ScratchProject/ -**/ScratchProjectWithInternals/ +src/.vs/config/applicationhost.config \ No newline at end of file diff --git a/SpotifyABClient/.gitignore b/SpotifyABClient/.gitignore index b253a6d..768cf90 100644 --- a/SpotifyABClient/.gitignore +++ b/SpotifyABClient/.gitignore @@ -384,4 +384,122 @@ InteropTests/NativeTests/out # Normally do not want to pick up changes in the scratch project, this will ignore files that aren't already tracked. # 'git update-index --assume-unchanged ' will allow ignoring changes for tracked files. **/ScratchProject/ -**/ScratchProjectWithInternals/ \ No newline at end of file +**/ScratchProjectWithInternals/ + +# Credits @ //github.com/aspnetboilerplate/aspnet-core-template/blob/master/.gitignore + +# Build Folders (you can keep bin if you'd like, to store dlls and pdbs) +[Bb]in/ +[Oo]bj/ + +# Logs +Logs/ + +# Generated files +project.lock.json +.vs/ + +# mstest test results +TestResults + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Rr]elease/ +x64/ +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.log +*.vspscc +*.vssscc +.builds + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper* + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish + +# Publish Web Output +*.Publish.xml + +# NuGet Packages Directory +packages + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +[Bb]in +[Oo]bj +sql +[Tt]est[Rr]esult* +*.Cache +ClientBin +[Ss]tyle[Cc]op.* +~$* +*.dbmdl +Generated_Code #added for RIA/Silverlight projects + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +src/.vs/config/applicationhost.config \ No newline at end of file diff --git a/SpotifyABClient/Dashboard.Designer.cs b/SpotifyABClient/Dashboard.Designer.cs index 60c8f37..167fded 100644 --- a/SpotifyABClient/Dashboard.Designer.cs +++ b/SpotifyABClient/Dashboard.Designer.cs @@ -1,4 +1,5 @@ -namespace SpotifyAB + +namespace SpotifyAB { partial class Dashboard { @@ -35,8 +36,7 @@ private void InitializeComponent() issuebtn = new Button(); devbtn = new Button(); groupBox1 = new GroupBox(); - uninstallABbtn = new Button(); - overri = new Button(); + uninstallBtn = new Button(); groupBox1.SuspendLayout(); SuspendLayout(); // @@ -103,7 +103,7 @@ private void InitializeComponent() // devbtn // devbtn.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; - devbtn.Location = new Point(642, 499); + devbtn.Location = new Point(642, 525); devbtn.Name = "devbtn"; devbtn.Size = new Size(301, 110); devbtn.TabIndex = 4; @@ -114,36 +114,25 @@ private void InitializeComponent() // groupBox1 // groupBox1.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; - groupBox1.Controls.Add(uninstallABbtn); + groupBox1.Controls.Add(uninstallBtn); groupBox1.Controls.Add(installBtn); - groupBox1.Location = new Point(12, 365); + groupBox1.Location = new Point(12, 383); groupBox1.Name = "groupBox1"; - groupBox1.Size = new Size(304, 244); + groupBox1.Size = new Size(304, 252); groupBox1.TabIndex = 5; groupBox1.TabStop = false; groupBox1.Text = "SpotifyAB Management"; // - // uninstallABbtn + // uninstallBtn // - uninstallABbtn.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; - uninstallABbtn.Location = new Point(6, 144); - uninstallABbtn.Name = "uninstallABbtn"; - uninstallABbtn.Size = new Size(292, 94); - uninstallABbtn.TabIndex = 6; - uninstallABbtn.Text = "Uninstall AB from Spotify"; - uninstallABbtn.UseVisualStyleBackColor = true; - uninstallABbtn.Click += uninstallABbtn_Click; - // - // overri - // - overri.Anchor = AnchorStyles.Bottom; - overri.Location = new Point(397, 535); - overri.Name = "overri"; - overri.Size = new Size(161, 74); - overri.TabIndex = 6; - overri.Text = "Override Options"; - overri.UseVisualStyleBackColor = true; - overri.Click += overri_Click; + uninstallBtn.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + uninstallBtn.Location = new Point(6, 142); + uninstallBtn.Name = "uninstallBtn"; + uninstallBtn.Size = new Size(292, 104); + uninstallBtn.TabIndex = 6; + uninstallBtn.Text = "Uninstall AB from Spotify"; + uninstallBtn.UseVisualStyleBackColor = true; + uninstallBtn.Click += uninstallABbtn_Click; // // Dashboard // @@ -152,8 +141,7 @@ private void InitializeComponent() AutoScaleDimensions = new SizeF(13F, 25F); AutoScaleMode = AutoScaleMode.Font; BackColor = SystemColors.Control; - ClientSize = new Size(955, 621); - Controls.Add(overri); + ClientSize = new Size(955, 647); Controls.Add(groupBox1); Controls.Add(devbtn); Controls.Add(issuebtn); @@ -167,12 +155,10 @@ private void InitializeComponent() StartPosition = FormStartPosition.CenterScreen; Text = "SpotifyAB Dashboard"; WindowState = FormWindowState.Maximized; - Load += Dashboard_Load; groupBox1.ResumeLayout(false); ResumeLayout(false); PerformLayout(); } - #endregion @@ -181,8 +167,7 @@ private void InitializeComponent() private Button issuebtn; private Button devbtn; private GroupBox groupBox1; - private Button uninstallABbtn; - private Button overri; - private static TextBox logBox; + private Button uninstallBtn; + private TextBox logBox; } } diff --git a/SpotifyABClient/Dashboard.cs b/SpotifyABClient/Dashboard.cs index 5a7375d..797c5b6 100644 --- a/SpotifyABClient/Dashboard.cs +++ b/SpotifyABClient/Dashboard.cs @@ -3,609 +3,444 @@ using SharpCompress.Readers; using System.Diagnostics; using System.Runtime.InteropServices; -using System.Timers; +using Windows.UI.Notifications; - -namespace SpotifyAB; - -public partial class Dashboard : Form +namespace SpotifyAB { - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool FlashWindow(IntPtr hwnd, bool bInvert); - private ToolTip toolTip1; // Declare ToolTip component - - public Dashboard() + public partial class Dashboard : Form { - InitializeComponent(); + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool FlashWindow(IntPtr hwnd, bool bInvert); - BlockSpotify(); - - // Call startup method - startup(); - log("SpotifyAB has successfully started"); - } + private ToolTip toolTip1; + public Dashboard() + { + InitializeComponent(); + BlockSpotify(); + Startup(this); + Log("SpotifyAB started successfully."); + } + // Block Spotify from running while SpotifyAB is running + private void BlockSpotify() + { + var timer = new System.Timers.Timer(); + timer.Interval = 1500; // Check every 1.5 seconds + timer.Elapsed += CheckAndKillSpotify; + timer.Start(); + } - // Block Spotify from running while SpotifyAB is running - private void BlockSpotify() - { - var timer = new System.Timers.Timer(); - timer.Interval = 1500; // Check every 1.5 seconds - timer.Elapsed += CheckAndKillSpotify; - timer.Start(); - } + private void CheckAndKillSpotify(object sender, EventArgs e) + { + try + { + var processes = Process.GetProcessesByName("Spotify"); + foreach (var process in processes.Where(p => !p.HasExited)) + { + process.EnableRaisingEvents = true; + process.Exited += (s, args) => Invoke((MethodInvoker)delegate { FlashWindow(Handle, true); }); + process.Kill(); + Log("Spotify closed to avoid conflicts."); + } + } + catch (Exception ex) + { + ShowError(this, $"Error: {ex.Message}"); + } + } - private void CheckAndKillSpotify(object sender, ElapsedEventArgs e) - { - try + public void Startup(Dashboard dashboard) { - var processes = Process.GetProcessesByName("Spotify"); - if (processes.Length > 0) + Log("Starting SpotifyAB"); + + dashboard.toolTip1 = new ToolTip(); + dashboard.toolTip1.SetToolTip(dashboard.linkLabel1, "Visit SpotifyAB's GitHub Repository"); + + if (IsSpotifyInstalled()) { - foreach (var process in processes) + Log("Spotify is installed."); + var currentVersion = GetSpotifyVersion(); + var savedVersion = GetRegistryKey("SpotifyVersion"); + if (string.IsNullOrEmpty(savedVersion)) + { + CheckSpotifyABInstallation(dashboard); + } + else if (currentVersion != savedVersion) { - if (!process.HasExited) + SetRegistryKey("Installed", "False"); + Log("Spotify version has changed. Reinstalling SpotifyAB on in this new version."); + if (MessageBox.Show("Spotify version has changed. Reinstall SpotifyAB?", "Update SpotifyAB", MessageBoxButtons.YesNo) == DialogResult.Yes) { - process.EnableRaisingEvents = true; - process.Exited += (s, args) => - { - this.Invoke((MethodInvoker)delegate - { - FlashWindow(this.Handle, true); // Flash the window in the taskbar - }); - }; - process.Kill(); - log("Spotify has been closed in order to avoid conflicts with SpotifyAB."); + DownloadAndInstallSpotifyAB(dashboard).Wait(); + Log("SpotifyAB reinstalled."); + } + else + { + CheckSpotifyABInstallation(dashboard); + Log("SpotifyAB not reinstalled."); } } + else + { + CheckSpotifyABInstallation(dashboard); + } } - } - catch (Exception ex) - { - this.Invoke((MethodInvoker)delegate + else { - MessageBox.Show($"An error occurred: {ex.Message}", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); // Show error message if an exception occurs while checking if Spotify is running - }); + HandleSpotifyNotInstalled(dashboard); + } } - } + private string GetRegistryKey(string keyName) + { + using var key = Registry.CurrentUser.OpenSubKey("Software\\SpotifyAB"); + return key?.GetValue(keyName)?.ToString(); + } - public void startup() - { - log("Starting SpotifyAB"); + private bool IsSpotifyInstalled() => + File.Exists($@"C:\Users\{Environment.UserName}\AppData\Roaming\Spotify\Spotify.exe"); - // Initialize ToolTip component - toolTip1 = new ToolTip(); + private void CheckSpotifyABInstallation(Dashboard dashboard) + { + var installed = IsSpotifyABInstalled(); + if (installed) SetRegistryKey("SpotifyVersion", GetSpotifyVersion()); + dashboard.installBtn.Enabled = !installed; + dashboard.uninstallBtn.Enabled = installed; + Log(installed ? "SpotifyAB is installed." : "SpotifyAB is not installed."); + } - // Associate ToolTip with LinkLabel control - toolTip1.SetToolTip(linkLabel1, "Visit SpotifyAB's GitHub Repository"); // Tooltip message for LinkLabel + private bool IsSpotifyABInstalled() => + Registry.CurrentUser.OpenSubKey("Software\\SpotifyAB")?.GetValue("Installed")?.ToString() == "True"; - // Check if Spotify is Installed - if (File.Exists(@"C:\Users\" + Environment.UserName + @"\AppData\Roaming\Spotify\Spotify.exe")) + private void HandleSpotifyNotInstalled(Dashboard dashboard) { - log("Spotify is installed on this machine"); - // Check if SpotifyAB is already installed - var openSubKey = Registry.CurrentUser.OpenSubKey("Software\\SpotifyAB"); - var installed = 0; - if (openSubKey != null) - { - var value = openSubKey.GetValue("Installed"); - if (value.ToString() == "True") installed = 1; - } + Log("Spotify is not installed."); + ShowError(dashboard, "Please install Spotify first. SpotifyAB only works with the desktop version."); + if (MessageBox.Show("Open Spotify download page?", "Download Spotify", MessageBoxButtons.YesNo) == DialogResult.Yes) + OpenUrl("https://www.spotify.com/download/windows/#download-cdn"); - if (installed == 1) + SetRegistryKey("Installed", "False"); + DisableButtons(dashboard); + } + + private void SetRegistryKey(string keyName, string value) + { + try { - installBtn.Enabled = false; - uninstallABbtn.Enabled = true; - log("It seems, that SpotifyAB is already installed."); + using var key = Registry.CurrentUser.CreateSubKey("Software\\SpotifyAB"); + key.SetValue(keyName, value); } - else + catch (Exception ex) { - installBtn.Enabled = true; - uninstallABbtn.Enabled = false; - log("It seems, that SpotifyAB is not yet installed."); + ShowError(null, $"Error saving to registry: {ex.Message}"); + Log($"Registry error: {ex.InnerException}"); } } - else + + private void DisableButtons(Dashboard dashboard) + { + dashboard.installBtn.Enabled = false; + dashboard.uninstallBtn.Enabled = false; + dashboard.devbtn.Enabled = false; + } + + public void Log(string message) + { + if (logBox.Lines.Length > 1000) logBox.Clear(); + logBox.AppendText($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] - {message}\r\n"); + } + + private void ShowError(Dashboard dashboard, string message) { - log("Spotify is not installed on this machine. Or at least not the correct version."); - log("Install Spotify (direct link): https://download.scdn.co/SpotifySetup.exe"); - MessageBox.Show( - "Please install Spotify first.\r\nNote: SpotifyAB works only on Windows Desktop (Microsoft store version is not supported.)", - "Not Installed", MessageBoxButtons.OK, - MessageBoxIcon.Error); // Show error message if Spotify is not installed - var answer = MessageBox.Show("Do you want to open the Spotify download page?", "Download Spotify", - MessageBoxButtons.YesNo, - MessageBoxIcon.Question); // Show confirmation message before opening the Spotify download page - if (answer == DialogResult.Yes) + if (dashboard != null) { - string url = "https://www.spotify.com/download/windows/#download-cdn"; // Set Spotify download page URL - try - { - // Open URL in default web browser - Process.Start(new ProcessStartInfo - { - FileName = url, - UseShellExecute = true - }); - } - catch (Exception ex) - { - MessageBox.Show($"An error occurred: {ex.Message}", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); // Show error message if an exception occurs while opening URL - } - } // Open the Spotify download page + dashboard.Invoke((MethodInvoker)delegate { MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); }); + } else { - log("Spotify download page has been canceled."); + MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } + } - // put Registry key to false + private void OpenUrl(string url) + { try { - var key = Registry.CurrentUser.CreateSubKey("Software\\SpotifyAB"); - key.SetValue("Installed", "False"); - key.Close(); + Process.Start(new ProcessStartInfo { FileName = url, UseShellExecute = true }); } - catch (Exception r) + catch (Exception ex) { - MessageBox.Show($"An error occurred: {r.Message}", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); - log("An error occurred while saving success to registry (CurrentUser\\Software\\SpotifyAB)"); - log(r.InnerException.ToString()); + ShowError(null, $"Error opening URL: {ex.Message}"); } - - // Disable all buttons - installBtn.Enabled = false; - uninstallABbtn.Enabled = false; - devbtn.Enabled = false; } - } - public static void log(string message) - { - //Check if the TextBox has reached the maximum number of lines - if (logBox.Lines.Length > 1000) - // Clear TextBox if the maximum number of lines is reached - logBox.Clear(); - - //get the current date and time - var dateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); - - // Append message to TextBox - logBox.AppendText($"[{dateTime}] - {message}\r\n"); - } - - private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) - { - var url = "https://www.github.com/An0n-00/SpotifyAB"; // Set Repository URL - - try - { - // Open URL in default web browser - Process.Start(new ProcessStartInfo - { - FileName = url, - UseShellExecute = true - }); - } - catch (Exception ex) - { - MessageBox.Show($"An error occurred: {ex.Message}", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); // Show error message if an exception occurs while opening URL - } - } + private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) => + OpenUrl("https://www.github.com/An0n-00/SpotifyAB"); - private async void installBtn_Click(object sender, EventArgs e) - { - try + private async void installBtn_Click(object sender, EventArgs e) { - int success = 0; - var fileUrl = "https://github.com/An0n-00/SpotifyAB/releases/latest/download/xpui.spa"; - var downloadPath = AppDomain.CurrentDomain.BaseDirectory + "\\xpui.spa"; - var destinationPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + - "\\Spotify\\Apps\\xpui.spa"; - - var openSubKey = Registry.CurrentUser.OpenSubKey("Software\\SpotifyAB"); - var installed = 0; - - // Check if spotifyAB is already installed - if (openSubKey != null) + if (!IsSpotifyInstalledProperly()) { - var value = openSubKey.GetValue("Installed"); - if (value.ToString() == "True") installed = 1; + ShowError(this, "Spotify is installed strangely. I cannot find the XPUI file."); + Log("Error: Cannot find the XPUI file"); + return; } + await DownloadAndInstallSpotifyAB(this); + installBtn.Enabled = false; + uninstallBtn.Enabled = true; + } - // Backup the original file - if (File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + - "\\Spotify\\Apps\\xpui.spa") && installed != 1) + private bool IsSpotifyInstalledProperly() + { + if (File.Exists($@"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\Spotify\Apps\xpui.spa")) { - if (File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + - "\\Spotify\\Apps\\xpui-original.spa")) - File.Delete(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + - "\\Spotify\\Apps\\xpui-original.spa"); - - File.Move(destinationPath, - Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + - "\\Spotify\\Apps\\xpui-original.spa"); + return true; } else { - MessageBox.Show( - "Spotify is not installed properly on this machine. Please reinstall Spotify first.", - "Broken Install", MessageBoxButtons.OK, MessageBoxIcon.Error); - log("Spotify is not installed properly on this machine. Please reinstall Spotify first."); - log("Install Spotify (direct link): https://download.scdn.co/SpotifySetup.exe"); - success = 1; - return; + if (File.Exists($@"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\Spotify\Apps\xpui-original.spa")) + { + File.Move($@"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\Spotify\Apps\xpui-original.spa", $@"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\Spotify\Apps\xpui.spa"); + return true; + } + else + { + return false; + } } + } + + private async Task DownloadAndInstallSpotifyAB(Dashboard dashboard) + { + var fileUrl = "https://github.com/An0n-00/SpotifyAB/releases/latest/download/xpui.spa"; + var downloadPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "xpui.spa"); + var destinationPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Spotify\\Apps\\xpui.spa"); + + BackupOriginalFile(destinationPath); try { - using (var client = new HttpClient()) + int success = 0; + + try { - using (var response = await client.GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead)) + using (var client = new HttpClient()) { - // Disable all controls in the current form - Enabled = false; - - // Create a new form with a progress bar - // Create a new form with a progress bar - var progressForm = new Form - { - Size = new Size(399, 110), // Set the initial size - MinimumSize = new Size(399, 109), // Set the minimum size - MaximumSize = new Size(400, 110), // Set the maximum size - StartPosition = FormStartPosition.CenterScreen, // Set the start position - Text = "Installing AB" // Set the title - }; - - var progressBar = new ProgressBar - { Style = ProgressBarStyle.Continuous, Dock = DockStyle.Fill }; - progressForm.Controls.Add(progressBar); - progressForm.Show(); - - var contentLength = response.Content.Headers.ContentLength.GetValueOrDefault(); - var totalBytes = 0L; - - using (var stream = new FileStream(downloadPath, FileMode.Create, FileAccess.Write, - FileShare.None)) + using (var response = await client.GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead)) { - var buffer = new byte[8192]; - var length = 0; + // Disable all controls in the current form + dashboard.Enabled = false; - while ((length = await response.Content.ReadAsStreamAsync().Result - .ReadAsync(buffer, 0, buffer.Length)) > 0) + // Create a new form with a progress bar + // Create a new form with a progress bar + var progressForm = new Form + { + Size = new Size(399, 110), // Set the initial size + MinimumSize = new Size(399, 109), // Set the minimum size + MaximumSize = new Size(400, 110), // Set the maximum size + StartPosition = FormStartPosition.CenterScreen, // Set the start position + Text = "Installing AB" // Set the title + }; + + var progressBar = new ProgressBar + { Style = ProgressBarStyle.Continuous, Dock = DockStyle.Fill }; + progressForm.Controls.Add(progressBar); + progressForm.Show(); + + var contentLength = response.Content.Headers.ContentLength.GetValueOrDefault(); + var totalBytes = 0L; + + using (var stream = new FileStream(downloadPath, FileMode.Create, FileAccess.Write, FileShare.None)) { - await stream.WriteAsync(buffer, 0, length); - totalBytes += length; + var buffer = new byte[8192]; + var length = 0; - // Update the progress bar - progressBar.Value = (int)((double)totalBytes / contentLength * 100); + while ((length = await response.Content.ReadAsStreamAsync().Result.ReadAsync(buffer, 0, buffer.Length)) > 0) + { + await stream.WriteAsync(buffer, 0, length); + totalBytes += length; + + // Update the progress bar + progressBar.Value = (int)((double)totalBytes / contentLength * 100); + } } - } - // Close the progress form and enable all controls in the current form - progressForm.Close(); - Enabled = true; + // Close the progress form and enable all controls in the current form + progressForm.Close(); + dashboard.Enabled = true; + } } } - } - catch (Exception d) - { - MessageBox.Show($"An error occurred: {d.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - log("An error occurred while downloading the file."); - log(d.InnerException.ToString()); - success = 1; - return; - } - - // Move the downloaded file to the Spotify directory - try - { - if (installed == 1) File.Delete(destinationPath); - File.Move(downloadPath, destinationPath); + catch (Exception d) + { + ShowError(dashboard, $"An error occurred: {d.Message}"); + Log("An error occurred while downloading the file."); + Log(d.InnerException.ToString()); + success = 1; + return; + } - // Unzip the file + // Move the downloaded file to the Spotify directory try { - using (var stream = File.OpenRead(destinationPath)) - using (var reader = ReaderFactory.Open(stream)) + if (success == 1) { + File.Delete(destinationPath); + Log("An error occurred while downloading the file."); + throw new Exception("An error occurred while downloading the file."); + } + + File.Move(downloadPath, destinationPath); + + // Unzip the file + try { - while (reader.MoveToNextEntry()) + using (var stream = File.OpenRead(destinationPath)) + using (var reader = ReaderFactory.Open(stream)) { - if (!reader.Entry.IsDirectory) + while (reader.MoveToNextEntry()) { - reader.WriteEntryToDirectory(Path.GetDirectoryName(destinationPath), new ExtractionOptions() { ExtractFullPath = true, Overwrite = true }); + if (!reader.Entry.IsDirectory) + { + reader.WriteEntryToDirectory(Path.GetDirectoryName(destinationPath), new ExtractionOptions() { ExtractFullPath = true, Overwrite = true }); + } } } } + catch (Exception ex) + { + ShowError(dashboard, $"An error occurred while unzipping the file: {ex.Message}"); + Log("An error occurred while unzipping the file."); + Log(ex.InnerException.ToString()); + throw new Exception("An error occurred while unzipping the file."); + } } - catch (Exception ex) + catch (Exception m) { - MessageBox.Show($"An error occurred while unzipping the file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - log("An error occurred while unzipping the file."); - log(ex.InnerException.ToString()); - success = 1; - return; + ShowError(dashboard, $"An error occurred: {m.Message}"); + Log("An error occurred while moving the file."); + Log(m.InnerException.ToString()); + throw new Exception("An error occurred while moving the file."); } - } - catch (Exception m) - { - MessageBox.Show($"An error occurred: {m.Message}", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); - log("An error occurred while moving the file."); - log(m.InnerException.ToString()); - success = 1; - return; - } - - try - { - // Open the key or create it if it doesn't exist - var key = Registry.CurrentUser.CreateSubKey("Software\\SpotifyAB"); - - // Set the value - key.SetValue("Installed", "True"); - // Close the key - key.Close(); - } - catch (Exception r) - { - MessageBox.Show($"An error occurred: {r.Message}", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); - log("An error occurred while saving success to registry (CurrentUser\\Software\\SpotifyAB)"); - log(r.InnerException.ToString()); - success = 1; + SetRegistryKey("Installed", "True"); + + Log("SpotifyAB installed successfully."); + ShowSuccess("SpotifyAB installed successfully."); } - - if (success != 1) + catch (Exception f) { - MessageBox.Show("SpotifyAB has been installed successfully.\r\nEnjoy your music!", "Success", - MessageBoxButtons.OK, MessageBoxIcon.Exclamation); - log("SpotifyAB has been installed successfully."); - installBtn.Enabled = false; - uninstallABbtn.Enabled = true; + ShowError(dashboard, $"An error occurred: {f.Message}"); } + // Save the Spotify version in the registry + var spotifyVersion = GetSpotifyVersion(); + SetRegistryKey("SpotifyVersion", spotifyVersion); + SetRegistryKey("Installed", "True"); } - catch (Exception f) + + private string GetSpotifyVersion() { - MessageBox.Show($"An error occurred: {f.Message}", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); + var spotifyExecutable = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Spotify\\Spotify.exe"); + return File.Exists(spotifyExecutable) ? FileVersionInfo.GetVersionInfo(spotifyExecutable).FileVersion : string.Empty; } - } - private void issuebtn_Click(object sender, EventArgs e) - { - var url = "https://www.github.com/An0n-00/SpotifyAB/issues"; // Set Repository URL - - try + private void BackupOriginalFile(string destinationPath) { - // Open URL in default web browser - Process.Start(new ProcessStartInfo + if (File.Exists(destinationPath) && !IsSpotifyABInstalled()) { - FileName = url, - UseShellExecute = true - }); + File.Move(destinationPath, destinationPath.Replace(".spa", "-original.spa")); + } + Thread.Sleep(1000); } - catch (Exception ex) + + private void ShowSuccess(string message) { - MessageBox.Show($"An error occurred: {ex.Message}", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); // Show error message if an exception occurs while opening URL + MessageBox.Show(message, "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + Log(message); } - } - private int DownloadAndRunScript(ref int success) - { - try + private void issuebtn_Click(object sender, EventArgs e) => + OpenUrl("https://www.github.com/An0n-00/SpotifyAB/issues"); + + private async void devbtn_Click(object sender, EventArgs e) { - var scriptUrl = - "https://raw.githubusercontent.com/An0n-00/SpotifyAB/refs/heads/main/analyze-tools/dev-tools/Enable-Dev-Tools-for-spotify.ps1"; - var installationFolder = AppDomain.CurrentDomain.BaseDirectory + "\\addons\\"; - var scriptPath = installationFolder + "enable-dev.ps1"; - if (!Directory.Exists(installationFolder)) Directory.CreateDirectory(installationFolder); - // Download the script - using (var client = new HttpClient()) + if (MessageBox.Show("Enable Developer Tools for Spotify?", "Enable Developer Tools", MessageBoxButtons.YesNo) == DialogResult.Yes) { - var content = client.GetByteArrayAsync(scriptUrl).Result; - File.WriteAllBytes(scriptPath, content); - } - var process = new Process(); - process.StartInfo.FileName = "powershell.exe"; - process.StartInfo.Arguments = $"-ExecutionPolicy Bypass -File \"{scriptPath}\""; - process.StartInfo.UseShellExecute = false; - process.StartInfo.CreateNoWindow = true; - process.StartInfo.RedirectStandardOutput = true; - process.Start(); - IntPtr maxWorkingSet = process.MaxWorkingSet; - process.WaitForExit(); - int exitCode = process.ExitCode; - if (exitCode == 0) - { - return success = 0; - } - else if (exitCode == 1) - { - return success = 1; - } - else if (exitCode == 2) - { - return success = 2; - } - else if (exitCode == 3) - { - return success = 3; - } - else if (success == 4) - { - return success = 4; - } - else if (success == 5) - { - return success = 5; + var success = await DownloadAndRunScript(); + Log(success == 0 ? "Developer Tools enabled succesfully." : "Error enabling Developer Tools."); } else { - return success = 1; + Log("Developer Tools enable cancelled."); } } - catch (Exception e) - { - MessageBox.Show($"An error occurred: {e.Message}", "Error", MessageBoxButtons.OK, - MessageBoxIcon - .Error); // Show error message if an exception occurs while downloading and running the PowerShell script - return success = 1; - throw; - } - } - private void devbtn_Click(object sender, EventArgs e) - { - var answer = MessageBox.Show("Are you sure you want to enable Developer Tools for Spotify?", - "Enable Developer Tools", MessageBoxButtons.YesNo, - MessageBoxIcon.Question); // Show confirmation message before enabling Developer Tools - if (answer != DialogResult.Yes) - { - log("Enabling Developer Tools for Spotify has been canceled."); - } - else + private async Task DownloadAndRunScript() { - var success = 0; - DownloadAndRunScript(ref success); - if (success == 0) - log("Developer Tools for Spotify has been enabled successfully. Depending on the version, the dev tools will only work one time until you enable them again."); - else if (success == 1) - log("An unknown error occurred while enabling Developer Tools for Spotify."); - else if (success == 2) - log("Could not find Spotify.exe"); - else if (success == 3) - log("Please login to Spotify first."); - else if (success == 4) - log("Could not find Spotify.exe"); - else if (success == 5) - log("Please login to Spotify first."); - - } - } + try + { + var scriptUrl = "https://raw.githubusercontent.com/An0n-00/SpotifyAB/refs/heads/main/analyze-tools/dev-tools/Enable-Dev-Tools-for-spotify.ps1"; + var scriptPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "addons", "enable-dev.ps1"); - private void uninstallABbtn_Click(object sender, EventArgs e) - { - var key = Registry.CurrentUser.OpenSubKey("Software\\SpotifyAB", true); - var success = 0; + Directory.CreateDirectory(Path.GetDirectoryName(scriptPath)); + using var client = new HttpClient(); + var content = await client.GetByteArrayAsync(scriptUrl); + await File.WriteAllBytesAsync(scriptPath, content); - // Check if the key exists - if (key != null) - { - // Read the value - var value = key.GetValue("Installed"); - - if (value == null) - { - MessageBox.Show("SpotifyAB is not installed on this machine.", - "Not Installed", MessageBoxButtons.OK, MessageBoxIcon.Error); - success = 1; + return RunPowerShellScript(scriptPath); } - - // Check if the value exists - if (value.ToString() != "True") + catch (Exception ex) { - MessageBox.Show("SpotifyAB is not installed on this machine.", - "Not Installed", MessageBoxButtons.OK, MessageBoxIcon.Error); - success = 1; + ShowError(this, $"Error: {ex.Message}"); + return 1; } - else - { - try - { - // Set the value - key.SetValue("Installed", "False"); - - // Close the key - key.Close(); - } - catch (Exception r) - { - MessageBox.Show($"An error occurred: {r.Message}", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); - log($"Error: {r.Message}"); - success = 1; - } + } - try - { - // Delete the files - if (success == 0) - File.Delete(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + - "\\Spotify\\Apps\\xpui.spa"); - - if (success == 0) Directory.Delete(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + - "\\Spotify\\Apps\\xpui", true); - - // Restore the original - if (success == 0 && File.Exists( - Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + - "\\Spotify\\Apps\\xpui-original.spa")) - File.Move(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + - "\\Spotify\\Apps\\xpui-original.spa", - Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + - "\\Spotify\\Apps\\xpui.spa"); - } - catch (Exception ex) + private int RunPowerShellScript(string scriptPath) + { + var process = new Process + { + StartInfo = new ProcessStartInfo { - MessageBox.Show($"An error occurred: {ex.Message}", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); - log($"Error: {ex.Message}"); - success = 1; + FileName = "powershell.exe", + Arguments = $"-ExecutionPolicy Bypass -File \"{scriptPath}\"", + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardOutput = true } + }; - if (success == 0) - { - MessageBox.Show("SpotifyAB has been uninstalled successfully.", "Success", MessageBoxButtons.OK, - MessageBoxIcon.Information); - log("SpotifyAB has been uninstalled successfully."); - installBtn.Enabled = true; - uninstallABbtn.Enabled = false; - } - else - { - MessageBox.Show("An error occurred while uninstalling SpotifyAB.", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); - log("An error occurred while uninstalling SpotifyAB."); - } - } - } - else - { - MessageBox.Show("SpotifyAB is not installed on this machine.", - "Not Installed", MessageBoxButtons.OK, MessageBoxIcon.Error); - log("SpotifyAB is not installed on this machine."); + process.Start(); + process.WaitForExit(); + return process.ExitCode; } - } - - private void overri_Click(object sender, EventArgs e) - { - var answer = MessageBox.Show("Are you sure that you want to override SpotifyAB's behavior? You might have to do this when Spotify updates and removes the SpotifyAB files.", "Override", MessageBoxButtons.YesNo, MessageBoxIcon.Question); - if (answer == DialogResult.Yes) + private void uninstallABbtn_Click(object sender, EventArgs e) { - // start overri.cs form - log("Showing override window."); - var form = new OverrideSpotifyAB(); - form.Show(); - } - else - { - log("Overriding SpotifyAB's behavior has been canceled."); + if (!IsSpotifyABInstalled()) + { + ShowError(this, "SpotifyAB is not installed."); + return; + } + + DeleteSpotifyABFiles(); + ShowSuccess("SpotifyAB uninstalled successfully."); + installBtn.Enabled = true; + uninstallBtn.Enabled = false; + SetRegistryKey("Installed", "False"); } - } - private void Dashboard_Load(object sender, EventArgs e) - { + private void DeleteSpotifyABFiles() + { + var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + var xpuiPath = Path.Combine(appDataPath, "Spotify\\Apps\\xpui.spa"); + var xpuiOriginalPath = Path.Combine(appDataPath, "Spotify\\Apps\\xpui-original.spa"); + if (File.Exists(xpuiPath)) File.Delete(xpuiPath); + if (Directory.Exists(Path.Combine(appDataPath, "Spotify\\Apps\\xpui"))) Directory.Delete(Path.Combine(appDataPath, "Spotify\\Apps\\xpui"), true); + if (File.Exists(xpuiOriginalPath)) File.Move(xpuiOriginalPath, xpuiPath); + } } } \ No newline at end of file diff --git a/SpotifyABClient/Program.cs b/SpotifyABClient/Program.cs index 634ccf0..600e792 100644 --- a/SpotifyABClient/Program.cs +++ b/SpotifyABClient/Program.cs @@ -11,7 +11,8 @@ private static void Main() // To customize application configuration such as set high DPI settings or default font, // see https://aka.ms/applicationconfiguration. ApplicationConfiguration.Initialize(); - Application.Run(new Dashboard()); + Dashboard dashboard = new Dashboard(); + Application.Run(dashboard); } } } \ No newline at end of file diff --git a/SpotifyABClient/SpotifyAB.csproj.user b/SpotifyABClient/SpotifyAB.csproj.user index 6a71edd..d33e4a2 100644 --- a/SpotifyABClient/SpotifyAB.csproj.user +++ b/SpotifyABClient/SpotifyAB.csproj.user @@ -7,8 +7,5 @@ Form - - Form - \ No newline at end of file diff --git a/SpotifyABClient/Spotify_logo_without_text.svg b/SpotifyABClient/Spotify_logo_without_text.svg new file mode 100644 index 0000000..de9a9c7 --- /dev/null +++ b/SpotifyABClient/Spotify_logo_without_text.svg @@ -0,0 +1,4 @@ + + + + diff --git a/SpotifyABClient/overri.Designer.cs b/SpotifyABClient/overri.Designer.cs deleted file mode 100644 index d9fb4db..0000000 --- a/SpotifyABClient/overri.Designer.cs +++ /dev/null @@ -1,109 +0,0 @@ -namespace SpotifyAB -{ - partial class OverrideSpotifyAB - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(OverrideSpotifyAB)); - isAlreadyInstalled = new Button(); - isNotInstalled = new Button(); - Back = new Button(); - label1 = new Label(); - SuspendLayout(); - // - // isAlreadyInstalled - // - isAlreadyInstalled.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; - isAlreadyInstalled.Location = new Point(12, 78); - isAlreadyInstalled.Name = "isAlreadyInstalled"; - isAlreadyInstalled.Size = new Size(161, 133); - isAlreadyInstalled.TabIndex = 0; - isAlreadyInstalled.Text = "SpotifyAB is already installed in Spotify."; - isAlreadyInstalled.UseVisualStyleBackColor = true; - isAlreadyInstalled.Click += isAlreadyInstalled_Click; - // - // isNotInstalled - // - isNotInstalled.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; - isNotInstalled.ImeMode = ImeMode.NoControl; - isNotInstalled.Location = new Point(246, 78); - isNotInstalled.Name = "isNotInstalled"; - isNotInstalled.Size = new Size(161, 133); - isNotInstalled.TabIndex = 1; - isNotInstalled.Text = "SpotifyAB is NOT installed in Spotify."; - isNotInstalled.UseVisualStyleBackColor = true; - isNotInstalled.Click += isNotInstalled_Click; - // - // Back - // - Back.Location = new Point(12, 217); - Back.Name = "Back"; - Back.Size = new Size(395, 114); - Back.TabIndex = 2; - Back.Text = "I was just playing around...\r\n(Back)"; - Back.UseVisualStyleBackColor = true; - Back.Click += Back_Click; - // - // label1 - // - label1.AutoSize = true; - label1.Font = new Font("Segoe UI", 11F); - label1.Location = new Point(12, 9); - label1.Name = "label1"; - label1.Size = new Size(150, 30); - label1.TabIndex = 1; - label1.Text = "I am sure that:"; - // - // OverrideSpotifyAB - // - AutoScaleDimensions = new SizeF(10F, 25F); - AutoScaleMode = AutoScaleMode.Font; - ClientSize = new Size(419, 343); - Controls.Add(label1); - Controls.Add(Back); - Controls.Add(isNotInstalled); - Controls.Add(isAlreadyInstalled); - FormBorderStyle = FormBorderStyle.FixedToolWindow; - Icon = (Icon)resources.GetObject("$this.Icon"); - MaximumSize = new Size(441, 399); - MinimumSize = new Size(441, 399); - Name = "OverrideSpotifyAB"; - ShowInTaskbar = false; - StartPosition = FormStartPosition.CenterScreen; - Text = "OverrideSpotifyAB"; - ResumeLayout(false); - PerformLayout(); - } - - #endregion - - private Button isAlreadyInstalled; - private Button isNotInstalled; - private Button Back; - private Label label1; - } -} \ No newline at end of file diff --git a/SpotifyABClient/overri.cs b/SpotifyABClient/overri.cs deleted file mode 100644 index bdd8aaf..0000000 --- a/SpotifyABClient/overri.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Microsoft.Win32; - -namespace SpotifyAB -{ - public partial class OverrideSpotifyAB : Form - { - public OverrideSpotifyAB() - { - InitializeComponent(); - } - - private void Back_Click(object sender, EventArgs e) - { - // Close the form - Dashboard.log("Override SpotifyAB form closed with no changes"); - this.Close(); - } - - private void isAlreadyInstalled_Click(object sender, EventArgs e) - { - var answer = MessageBox.Show("Are you sure that you want to override the current analysis of SpotifyAB?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); - if (answer == DialogResult.No) - { - return; - } - else if (answer == DialogResult.Yes) - { - try - { - // Open the key or create it if it doesn't exist - var key = Registry.CurrentUser.CreateSubKey("Software\\SpotifyAB"); - - // Set the value - key.SetValue("Installed", "True"); - - // Close the key - key.Close(); - - Dashboard.log("Change: SpotifyAB is already installed in Spotify"); - Dashboard.log("Note: Restart SpotifyAB for the changes to take effect"); - - MessageBox.Show("Please Restart SpotifyAB for the changes to take effect.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); - } - catch (Exception r) - { - MessageBox.Show($"An error occurred while Overriding: {r.Message}", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); - } - } - } - - private void isNotInstalled_Click(object sender, EventArgs e) - { - var answer = MessageBox.Show("Are you sure that you want to override the current analysis of SpotifyAB?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); - if (answer == DialogResult.No) - { - return; - } - else if (answer == DialogResult.Yes) - { - try - { - // Open the key or create it if it doesn't exist - var key = Registry.CurrentUser.CreateSubKey("Software\\SpotifyAB"); - - // Set the value - key.SetValue("Installed", "False"); - - // Close the key - key.Close(); - - - Dashboard.log("Change: SpotifyAB is NOT installed in Spotify"); - Dashboard.log("Note: Restart SpotifyAB for the changes to take effect"); - - MessageBox.Show("Please Restart SpotifyAB for the changes to take effect.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); - } - catch (Exception r) - { - MessageBox.Show($"An error occurred while Overriding: {r.Message}", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); - } - } - } - } -} diff --git a/SpotifyABClient/overri.resx b/SpotifyABClient/overri.resx deleted file mode 100644 index bd5f57d..0000000 --- a/SpotifyABClient/overri.resx +++ /dev/null @@ -1,381 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - - 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 - - - \ No newline at end of file