mirror of
https://github.com/chylex/TweetDuck.git
synced 2024-11-25 14:42:47 +01:00
Compare commits
No commits in common. "b1328e5b1f12cdcf7d06301bc958b2e9fda3be3f" and "b58c8f65feea50fd9b6297b005bca70372977ef0" have entirely different histories.
b1328e5b1f
...
b58c8f65fe
@ -11,8 +11,8 @@
|
|||||||
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
|
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
|
||||||
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||||
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||||
<option name="PROJECT_KIND" value="DotNetCore" />
|
<option name="PROJECT_KIND" value="Console" />
|
||||||
<option name="PROJECT_TFM" value="net6.0-windows7.0" />
|
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.2" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Build" />
|
<option name="Build" />
|
||||||
</method>
|
</method>
|
||||||
|
32
README.md
32
README.md
@ -43,14 +43,14 @@ Download links and system requirements are on the [official website](https://twe
|
|||||||
|
|
||||||
Building TweetDuck for Windows requires at minimum [Visual Studio 2019](https://visualstudio.microsoft.com/downloads) and Windows 7. Before opening the solution, open Visual Studio Installer and make sure you have the following Visual Studio workloads and components installed:
|
Building TweetDuck for Windows requires at minimum [Visual Studio 2019](https://visualstudio.microsoft.com/downloads) and Windows 7. Before opening the solution, open Visual Studio Installer and make sure you have the following Visual Studio workloads and components installed:
|
||||||
* **.NET desktop development**
|
* **.NET desktop development**
|
||||||
* .NET SDK
|
* .NET Framework 4.7.2 targeting pack
|
||||||
* F# desktop language support
|
* F# desktop language support
|
||||||
* **Desktop development with C++**
|
* **Desktop development with C++**
|
||||||
* MSVC v142 - VS 2019 C++ x64/x86 build tools (v14.20 / Latest)
|
* MSVC v142 - VS 2019 C++ x64/x86 build tools (v14.20 / Latest)
|
||||||
|
|
||||||
In the **Installation details** panel, you can expand the workloads you selected, and uncheck any components that are not listed above to save space. You may uncheck the .NET SDK component if you installed the [.NET 6 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) directly.
|
In the **Installation details** panel, you can expand the workloads you selected, and uncheck any components that are not listed above to save space.
|
||||||
|
|
||||||
Building TweetDuck for Linux requires [.NET 6 SDK](https://docs.microsoft.com/en-us/dotnet/core/install/linux). The Linux project has its own solution file in the `linux/` folder.
|
Building TweetDuck for Linux requires [.NET 5](https://docs.microsoft.com/en-us/dotnet/core/install/linux). The Linux project has its own solution file in the `linux/` folder.
|
||||||
|
|
||||||
### Editors
|
### Editors
|
||||||
|
|
||||||
@ -66,15 +66,15 @@ Icons and logos were designed in [Affinity Designer](https://affinity.serif.com/
|
|||||||
> If you don't want to build installers using the existing foundations, you can skip this section.
|
> If you don't want to build installers using the existing foundations, you can skip this section.
|
||||||
|
|
||||||
Official Windows installers are built using [InnoSetup](https://jrsoftware.org/isinfo.php) and [Inno Download Plugin](https://mitrichsoftware.wordpress.com/inno-setup-tools/inno-download-plugin/), specifically:
|
Official Windows installers are built using [InnoSetup](https://jrsoftware.org/isinfo.php) and [Inno Download Plugin](https://mitrichsoftware.wordpress.com/inno-setup-tools/inno-download-plugin/), specifically:
|
||||||
* [InnoSetup 6.2.1](https://files.jrsoftware.org/is/6/innosetup-6.2.1.exe)
|
* [InnoSetup 5.6.1](https://files.jrsoftware.org/is/5/innosetup-5.6.1.exe) with Preprocessor support
|
||||||
* [Inno Download Plugin 1.5.1](https://drive.google.com/folderview?id=0Bzw1xBVt0mokSXZrUEFIanV4azA&usp=sharing#list)
|
* [Inno Download Plugin 1.5.0](https://drive.google.com/folderview?id=0Bzw1xBVt0mokSXZrUEFIanV4azA&usp=sharing#list)
|
||||||
|
|
||||||
During installation, the download plugin will ask whether to add its include path to `ISPPBuiltins.iss`. Note that this option does not work with InnoSetup 6, so TweetDuck installers don't need it.
|
When installing InnoSetup, you can choose to include Inno Script Studio which I recommend for editing and testing installer configuration files in the `bld` folder (`.iss` extension).
|
||||||
|
|
||||||
Scripts for building installers require the `PATH` environment variable to include the InnoSetup installation folder. You can either edit `PATH` manually, or use a program like [Rapid Environment Editor](https://www.rapidee.com/en/about) to simplify the process. For example, this is the installation folder I added to `PATH` under **User variables**:
|
Scripts for building installers require the `PATH` environment variable to include the InnoSetup installation folder. You can either edit `PATH` manually, or use a program like [Rapid Environment Editor](https://www.rapidee.com/en/about) to simplify the process. For example, this is the installation folder I added to `PATH` under **User variables**:
|
||||||
* `C:\Program Files (x86)\Inno Setup 6`
|
* `C:\Program Files (x86)\Inno Setup 5`
|
||||||
|
|
||||||
You may need to restart Visual Studio or Rider after changing `PATH` for the change to take place.
|
You may need to restart Visual Studio after changing `PATH` for the change to take place.
|
||||||
|
|
||||||
## Solution Overview
|
## Solution Overview
|
||||||
|
|
||||||
@ -84,13 +84,13 @@ On Windows, TweetDuck uses the [CefSharp](https://github.com/cefsharp/CefSharp/)
|
|||||||
|
|
||||||
On Linux, TweetDuck uses the [ChromiumGtk](https://github.com/lunixo/ChromiumGtk) library, which combines [CefGlue](https://gitlab.com/xiliumhq/chromiumembedded/cefglue) for the browser component and [GtkSharp](https://github.com/GtkSharp/GtkSharp) for the GUI.
|
On Linux, TweetDuck uses the [ChromiumGtk](https://github.com/lunixo/ChromiumGtk) library, which combines [CefGlue](https://gitlab.com/xiliumhq/chromiumembedded/cefglue) for the browser component and [GtkSharp](https://github.com/GtkSharp/GtkSharp) for the GUI.
|
||||||
|
|
||||||
The solution contains several C# projects for executables and libraries, and F# projects for automated tests. All projects target `.NET 6` and either `C# 10` or `F#`.
|
The solution contains several C# projects for executables and libraries, and F# projects for automated tests.
|
||||||
|
|
||||||
Projects are organized into folders:
|
Projects are organized into folders:
|
||||||
* Windows projects are in the `windows/` folder
|
* Windows projects are in the `windows/` folder, and target `.NET Framework 4.7.2` + `C# 8.0`
|
||||||
* Linux projects are in the `linux/` folder
|
* Linux projects are in the `linux/` folder, and target `.NET 5` + `C#`
|
||||||
* Libraries (`TweetLib.*`) are in the `lib/` folder
|
* Libraries (`TweetLib.*`) are in the `lib/` folder, and target `.NET Standard 2.0` + `C# 9.0`
|
||||||
* Tests (`TweetTest.*`) are also in the `lib/` folder
|
* Tests (`TweetTest.*`) are also in the `lib/` folder, and target `.NET Framework 4.7.2` + `F#`
|
||||||
|
|
||||||
Here are a few things to keep in mind:
|
Here are a few things to keep in mind:
|
||||||
* Executable projects have their entry points in `Program.cs`
|
* Executable projects have their entry points in `Program.cs`
|
||||||
@ -130,7 +130,7 @@ Main Windows executable. It has a dependency on [CefSharp](https://github.com/ce
|
|||||||
|
|
||||||
#### TweetDuck.Browser
|
#### TweetDuck.Browser
|
||||||
|
|
||||||
Windows executable that hosts various Chromium processes. It has a dependency on [CefSharp](https://github.com/cefsharp/CefSharp/).
|
Windows executable that hosts various Chromium processes. It depends on two specific DLLs from the [CefSharp](https://github.com/cefsharp/CefSharp/) package. After updating [CefSharp](https://github.com/cefsharp/CefSharp/), run the `windows/TweetDuck/Resources/PostCefUpdate.ps1` PowerShell script to update these dependencies to the new version.
|
||||||
|
|
||||||
#### TweetDuck.Video
|
#### TweetDuck.Video
|
||||||
|
|
||||||
@ -142,10 +142,6 @@ By default, [CefSharp](https://github.com/cefsharp/CefSharp/) is not built with
|
|||||||
|
|
||||||
Windows library that implements `TweetLib.Browser.CEF` using the [CefSharp](https://github.com/cefsharp/CefSharp/) library and Windows Forms.
|
Windows library that implements `TweetLib.Browser.CEF` using the [CefSharp](https://github.com/cefsharp/CefSharp/) library and Windows Forms.
|
||||||
|
|
||||||
#### TweetLib.WinForms.Legacy
|
|
||||||
|
|
||||||
Windows library that re-adds some legacy Windows Forms components that were removed in .NET Core 3.1. The sources were taken from the [.NET Core 3.0 sources of Windows Forms](https://github.com/dotnet/winforms/tree/v3.0.2), and edited to remove unnecessary features.
|
|
||||||
|
|
||||||
### Linux Projects
|
### Linux Projects
|
||||||
|
|
||||||
#### TweetDuck
|
#### TweetDuck
|
||||||
|
@ -10,8 +10,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetDuck.Video", "windows\
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetImpl.CefSharp", "windows\TweetImpl.CefSharp\TweetImpl.CefSharp.csproj", "{44DF3E2E-F465-4A31-8B43-F40FFFB018BA}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetImpl.CefSharp", "windows\TweetImpl.CefSharp\TweetImpl.CefSharp.csproj", "{44DF3E2E-F465-4A31-8B43-F40FFFB018BA}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetLib.WinForms.Legacy", "windows\TweetLib.WinForms.Legacy\TweetLib.WinForms.Legacy.csproj", "{B54E732A-4090-4DAA-9ABD-311368C17B68}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetLib.Communication", "lib\TweetLib.Communication\TweetLib.Communication.csproj", "{72473763-4B9D-4FB6-A923-9364B2680F06}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetLib.Communication", "lib\TweetLib.Communication\TweetLib.Communication.csproj", "{72473763-4B9D-4FB6-A923-9364B2680F06}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetLib.Core", "lib\TweetLib.Core\TweetLib.Core.csproj", "{93BA3CB4-A812-4949-B07D-8D393FB38937}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetLib.Core", "lib\TweetLib.Core\TweetLib.Core.csproj", "{93BA3CB4-A812-4949-B07D-8D393FB38937}"
|
||||||
@ -50,10 +48,6 @@ Global
|
|||||||
{44DF3E2E-F465-4A31-8B43-F40FFFB018BA}.Debug|x86.Build.0 = Debug|x86
|
{44DF3E2E-F465-4A31-8B43-F40FFFB018BA}.Debug|x86.Build.0 = Debug|x86
|
||||||
{44DF3E2E-F465-4A31-8B43-F40FFFB018BA}.Release|x86.ActiveCfg = Release|x86
|
{44DF3E2E-F465-4A31-8B43-F40FFFB018BA}.Release|x86.ActiveCfg = Release|x86
|
||||||
{44DF3E2E-F465-4A31-8B43-F40FFFB018BA}.Release|x86.Build.0 = Release|x86
|
{44DF3E2E-F465-4A31-8B43-F40FFFB018BA}.Release|x86.Build.0 = Release|x86
|
||||||
{B54E732A-4090-4DAA-9ABD-311368C17B68}.Debug|x86.ActiveCfg = Debug|x86
|
|
||||||
{B54E732A-4090-4DAA-9ABD-311368C17B68}.Debug|x86.Build.0 = Debug|x86
|
|
||||||
{B54E732A-4090-4DAA-9ABD-311368C17B68}.Release|x86.ActiveCfg = Release|x86
|
|
||||||
{B54E732A-4090-4DAA-9ABD-311368C17B68}.Release|x86.Build.0 = Release|x86
|
|
||||||
{72473763-4B9D-4FB6-A923-9364B2680F06}.Debug|x86.ActiveCfg = Debug|x86
|
{72473763-4B9D-4FB6-A923-9364B2680F06}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
{72473763-4B9D-4FB6-A923-9364B2680F06}.Debug|x86.Build.0 = Debug|x86
|
{72473763-4B9D-4FB6-A923-9364B2680F06}.Debug|x86.Build.0 = Debug|x86
|
||||||
{72473763-4B9D-4FB6-A923-9364B2680F06}.Release|x86.ActiveCfg = Release|x86
|
{72473763-4B9D-4FB6-A923-9364B2680F06}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
@ -6,6 +6,6 @@
|
|||||||
|
|
||||||
namespace TweetDuck {
|
namespace TweetDuck {
|
||||||
internal static class Version {
|
internal static class Version {
|
||||||
public const string Tag = "1.23";
|
public const string Tag = "1.22.1";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
bld/Redist/api-ms-win-core-console-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-console-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-datetime-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-datetime-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-debug-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-debug-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-errorhandling-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-errorhandling-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-file-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-file-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-file-l1-2-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-file-l1-2-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-file-l2-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-file-l2-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-handle-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-handle-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-heap-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-heap-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-interlocked-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-interlocked-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-libraryloader-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-libraryloader-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-localization-l1-2-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-localization-l1-2-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-memory-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-memory-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-namedpipe-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-namedpipe-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-processenvironment-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-processenvironment-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-processthreads-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-processthreads-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-processthreads-l1-1-1.dll
Normal file
BIN
bld/Redist/api-ms-win-core-processthreads-l1-1-1.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-profile-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-profile-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-rtlsupport-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-rtlsupport-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-string-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-string-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-synch-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-synch-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-synch-l1-2-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-synch-l1-2-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-sysinfo-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-sysinfo-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-timezone-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-timezone-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-core-util-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-core-util-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-crt-conio-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-crt-conio-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-crt-convert-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-crt-convert-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-crt-environment-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-crt-environment-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-crt-filesystem-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-crt-filesystem-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-crt-heap-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-crt-heap-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-crt-locale-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-crt-locale-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-crt-math-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-crt-math-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-crt-multibyte-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-crt-multibyte-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-crt-private-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-crt-private-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-crt-process-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-crt-process-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-crt-runtime-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-crt-runtime-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-crt-stdio-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-crt-stdio-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-crt-string-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-crt-string-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-crt-time-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-crt-time-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/api-ms-win-crt-utility-l1-1-0.dll
Normal file
BIN
bld/Redist/api-ms-win-crt-utility-l1-1-0.dll
Normal file
Binary file not shown.
BIN
bld/Redist/concrt140.dll
Normal file
BIN
bld/Redist/concrt140.dll
Normal file
Binary file not shown.
BIN
bld/Redist/msvcp140.dll
Normal file
BIN
bld/Redist/msvcp140.dll
Normal file
Binary file not shown.
BIN
bld/Redist/msvcp140_1.dll
Normal file
BIN
bld/Redist/msvcp140_1.dll
Normal file
Binary file not shown.
BIN
bld/Redist/msvcp140_2.dll
Normal file
BIN
bld/Redist/msvcp140_2.dll
Normal file
Binary file not shown.
BIN
bld/Redist/msvcp140_atomic_wait.dll
Normal file
BIN
bld/Redist/msvcp140_atomic_wait.dll
Normal file
Binary file not shown.
BIN
bld/Redist/msvcp140_codecvt_ids.dll
Normal file
BIN
bld/Redist/msvcp140_codecvt_ids.dll
Normal file
Binary file not shown.
BIN
bld/Redist/ucrtbase.dll
Normal file
BIN
bld/Redist/ucrtbase.dll
Normal file
Binary file not shown.
BIN
bld/Redist/vccorlib140.dll
Normal file
BIN
bld/Redist/vccorlib140.dll
Normal file
Binary file not shown.
BIN
bld/Redist/vcruntime140.dll
Normal file
BIN
bld/Redist/vcruntime140.dll
Normal file
Binary file not shown.
@ -9,8 +9,6 @@
|
|||||||
|
|
||||||
#define MyAppVersion GetFileVersion("..\windows\TweetDuck\bin\x86\Release\TweetDuck.exe")
|
#define MyAppVersion GetFileVersion("..\windows\TweetDuck\bin\x86\Release\TweetDuck.exe")
|
||||||
|
|
||||||
#include ReadReg(HKLM, "Software\Mitrich Software\Inno Download Plugin", "InstallDir") + "\idp.iss"
|
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
AppId={{8C25A716-7E11-4AAD-9992-8B5D0C78AE06}
|
AppId={{8C25A716-7E11-4AAD-9992-8B5D0C78AE06}
|
||||||
AppName={#MyAppName}
|
AppName={#MyAppName}
|
||||||
@ -31,11 +29,13 @@ Uninstallable=TDIsUninstallable
|
|||||||
UninstallDisplayName={#MyAppName}
|
UninstallDisplayName={#MyAppName}
|
||||||
UninstallDisplayIcon={app}\{#MyAppExeName}
|
UninstallDisplayIcon={app}\{#MyAppExeName}
|
||||||
Compression=lzma2/ultra
|
Compression=lzma2/ultra
|
||||||
LZMADictionarySize=32768
|
LZMADictionarySize=15360
|
||||||
SolidCompression=yes
|
SolidCompression=yes
|
||||||
InternalCompressLevel=normal
|
InternalCompressLevel=normal
|
||||||
MinVersion=0,6.1
|
MinVersion=0,6.1
|
||||||
|
|
||||||
|
#include <idp.iss>
|
||||||
|
|
||||||
[Languages]
|
[Languages]
|
||||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||||
|
|
||||||
@ -68,11 +68,20 @@ AdditionalTasks=Additional shortcuts and components:
|
|||||||
var UpdatePath: String;
|
var UpdatePath: String;
|
||||||
var VisitedTasksPage: Boolean;
|
var VisitedTasksPage: Boolean;
|
||||||
|
|
||||||
{ Prepare installation variables. }
|
function TDGetNetFrameworkVersion: Cardinal; forward;
|
||||||
|
|
||||||
|
{ Check .NET Framework version on startup, ask user if they want to proceed if older than 4.7.2. }
|
||||||
function InitializeSetup: Boolean;
|
function InitializeSetup: Boolean;
|
||||||
begin
|
begin
|
||||||
UpdatePath := ExpandConstant('{param:UPDATEPATH}')
|
UpdatePath := ExpandConstant('{param:UPDATEPATH}')
|
||||||
VisitedTasksPage := False
|
VisitedTasksPage := False
|
||||||
|
|
||||||
|
if (TDGetNetFrameworkVersion() < 461808) and (MsgBox('{#MyAppName} requires .NET Framework 4.7.2 or newer,'+#13+#10+'please visit {#MyAppShortURL} for a download link.'+#13+#10+#13+#10'Do you want to proceed with the setup anyway?', mbCriticalError, MB_YESNO or MB_DEFBUTTON2) = IDNO) then
|
||||||
|
begin
|
||||||
|
Result := False
|
||||||
|
Exit
|
||||||
|
end;
|
||||||
|
|
||||||
Result := True
|
Result := True
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -131,3 +140,17 @@ function TDIsUninstallable: Boolean;
|
|||||||
begin
|
begin
|
||||||
Result := (UpdatePath = '')
|
Result := (UpdatePath = '')
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Return DWORD value containing the build version of .NET Framework. }
|
||||||
|
function TDGetNetFrameworkVersion: Cardinal;
|
||||||
|
var FrameworkVersion: Cardinal;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if RegQueryDWordValue(HKEY_LOCAL_MACHINE, 'Software\Microsoft\NET Framework Setup\NDP\v4\Full', 'Release', FrameworkVersion) then
|
||||||
|
begin
|
||||||
|
Result := FrameworkVersion
|
||||||
|
Exit
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := 0
|
||||||
|
end;
|
||||||
|
@ -9,8 +9,6 @@
|
|||||||
|
|
||||||
#define MyAppVersion GetFileVersion("..\windows\TweetDuck\bin\x86\Release\TweetDuck.exe")
|
#define MyAppVersion GetFileVersion("..\windows\TweetDuck\bin\x86\Release\TweetDuck.exe")
|
||||||
|
|
||||||
#include ReadReg(HKLM, "Software\Mitrich Software\Inno Download Plugin", "InstallDir") + "\idp.iss"
|
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
AppId={{8C25A716-7E11-4AAD-9992-8B5D0C78AE06}
|
AppId={{8C25A716-7E11-4AAD-9992-8B5D0C78AE06}
|
||||||
AppName={#MyAppName} Portable
|
AppName={#MyAppName} Portable
|
||||||
@ -31,11 +29,13 @@ Uninstallable=no
|
|||||||
UsePreviousAppDir=no
|
UsePreviousAppDir=no
|
||||||
PrivilegesRequired=lowest
|
PrivilegesRequired=lowest
|
||||||
Compression=lzma2/ultra
|
Compression=lzma2/ultra
|
||||||
LZMADictionarySize=32768
|
LZMADictionarySize=15360
|
||||||
SolidCompression=yes
|
SolidCompression=yes
|
||||||
InternalCompressLevel=normal
|
InternalCompressLevel=normal
|
||||||
MinVersion=0,6.1
|
MinVersion=0,6.1
|
||||||
|
|
||||||
|
#include <idp.iss>
|
||||||
|
|
||||||
[Languages]
|
[Languages]
|
||||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||||
|
|
||||||
@ -52,10 +52,19 @@ AdditionalTasks=Additional components:
|
|||||||
[Code]
|
[Code]
|
||||||
var UpdatePath: String;
|
var UpdatePath: String;
|
||||||
|
|
||||||
{ Prepare installation variables. }
|
function TDGetNetFrameworkVersion: Cardinal; forward;
|
||||||
|
|
||||||
|
{ Check .NET Framework version on startup, ask user if they want to proceed if older than 4.7.2. }
|
||||||
function InitializeSetup: Boolean;
|
function InitializeSetup: Boolean;
|
||||||
begin
|
begin
|
||||||
UpdatePath := ExpandConstant('{param:UPDATEPATH}')
|
UpdatePath := ExpandConstant('{param:UPDATEPATH}')
|
||||||
|
|
||||||
|
if (TDGetNetFrameworkVersion() < 461808) and (MsgBox('{#MyAppName} requires .NET Framework 4.7.2 or newer,'+#13+#10+'please visit {#MyAppShortURL} for a download link.'+#13+#10+#13+#10'Do you want to proceed with the setup anyway?', mbCriticalError, MB_YESNO or MB_DEFBUTTON2) = IDNO) then
|
||||||
|
begin
|
||||||
|
Result := False
|
||||||
|
Exit
|
||||||
|
end;
|
||||||
|
|
||||||
Result := True
|
Result := True
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -93,3 +102,17 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Return DWORD value containing the build version of .NET Framework. }
|
||||||
|
function TDGetNetFrameworkVersion: Cardinal;
|
||||||
|
var FrameworkVersion: Cardinal;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if RegQueryDWordValue(HKEY_LOCAL_MACHINE, 'Software\Microsoft\NET Framework Setup\NDP\v4\Full', 'Release', FrameworkVersion) then
|
||||||
|
begin
|
||||||
|
Result := FrameworkVersion
|
||||||
|
Exit
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := 0
|
||||||
|
end;
|
||||||
|
@ -11,8 +11,6 @@
|
|||||||
#define MyAppVersion GetFileVersion("..\windows\TweetDuck\bin\x86\Release\TweetDuck.exe")
|
#define MyAppVersion GetFileVersion("..\windows\TweetDuck\bin\x86\Release\TweetDuck.exe")
|
||||||
#define CefVersion GetFileVersion("..\windows\TweetDuck\bin\x86\Release\libcef.dll")
|
#define CefVersion GetFileVersion("..\windows\TweetDuck\bin\x86\Release\libcef.dll")
|
||||||
|
|
||||||
#include ReadReg(HKLM, "Software\Mitrich Software\Inno Download Plugin", "InstallDir") + "\idp.iss"
|
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
AppId={{{#MyAppID}}
|
AppId={{{#MyAppID}}
|
||||||
AppName={#MyAppName}
|
AppName={#MyAppName}
|
||||||
@ -39,6 +37,8 @@ SolidCompression=True
|
|||||||
InternalCompressLevel=normal
|
InternalCompressLevel=normal
|
||||||
MinVersion=0,6.1
|
MinVersion=0,6.1
|
||||||
|
|
||||||
|
#include <idp.iss>
|
||||||
|
|
||||||
[Languages]
|
[Languages]
|
||||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||||
|
|
||||||
@ -84,6 +84,7 @@ Type: filesandordirs; Name: "{app}\scripts"
|
|||||||
function TDIsUninstallable: Boolean; forward;
|
function TDIsUninstallable: Boolean; forward;
|
||||||
function TDGetRunArgs(Param: String): String; forward;
|
function TDGetRunArgs(Param: String): String; forward;
|
||||||
function TDFindUpdatePath: String; forward;
|
function TDFindUpdatePath: String; forward;
|
||||||
|
function TDGetNetFrameworkVersion: Cardinal; forward;
|
||||||
function TDGetAppVersionClean: String; forward;
|
function TDGetAppVersionClean: String; forward;
|
||||||
function TDGetFullDownloadFileName: String; forward;
|
function TDGetFullDownloadFileName: String; forward;
|
||||||
function TDIsMatchingCEFVersion: Boolean; forward;
|
function TDIsMatchingCEFVersion: Boolean; forward;
|
||||||
@ -92,7 +93,7 @@ procedure TDExecuteFullDownload; forward;
|
|||||||
var IsPortable: Boolean;
|
var IsPortable: Boolean;
|
||||||
var UpdatePath: String;
|
var UpdatePath: String;
|
||||||
|
|
||||||
{ Prepare update installation, and the full download package if required. }
|
{ Check .NET Framework version on startup, ask user if they want to proceed if older than 4.7.2. Prepare full download package if required. }
|
||||||
function InitializeSetup: Boolean;
|
function InitializeSetup: Boolean;
|
||||||
begin
|
begin
|
||||||
IsPortable := ExpandConstant('{param:PORTABLE}') = '1'
|
IsPortable := ExpandConstant('{param:PORTABLE}') = '1'
|
||||||
@ -110,6 +111,12 @@ begin
|
|||||||
idpAddFile('https://github.com/{#MyAppPublisher}/{#MyAppName}/releases/download/'+TDGetAppVersionClean()+'/'+TDGetFullDownloadFileName(), ExpandConstant('{tmp}\{#MyAppName}.Full.exe'))
|
idpAddFile('https://github.com/{#MyAppPublisher}/{#MyAppName}/releases/download/'+TDGetAppVersionClean()+'/'+TDGetFullDownloadFileName(), ExpandConstant('{tmp}\{#MyAppName}.Full.exe'))
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if (TDGetNetFrameworkVersion() < 461808) and (MsgBox('{#MyAppName} requires .NET Framework 4.7.2 or newer,'+#13+#10+'please visit {#MyAppShortURL} for a download link.'+#13+#10+#13+#10'Do you want to proceed with the setup anyway?', mbCriticalError, MB_YESNO or MB_DEFBUTTON2) = IDNO) then
|
||||||
|
begin
|
||||||
|
Result := False
|
||||||
|
Exit
|
||||||
|
end;
|
||||||
|
|
||||||
Result := True
|
Result := True
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -204,6 +211,20 @@ begin
|
|||||||
Result := Path
|
Result := Path
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Return DWORD value containing the build version of .NET Framework. }
|
||||||
|
function TDGetNetFrameworkVersion: Cardinal;
|
||||||
|
var FrameworkVersion: Cardinal;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if RegQueryDWordValue(HKEY_LOCAL_MACHINE, 'Software\Microsoft\NET Framework Setup\NDP\v4\Full', 'Release', FrameworkVersion) then
|
||||||
|
begin
|
||||||
|
Result := FrameworkVersion
|
||||||
|
Exit
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := 0
|
||||||
|
end;
|
||||||
|
|
||||||
{ Return the name of the full installer file to download from GitHub. }
|
{ Return the name of the full installer file to download from GitHub. }
|
||||||
function TDGetFullDownloadFileName: String;
|
function TDGetFullDownloadFileName: String;
|
||||||
begin
|
begin
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"sdk": {
|
|
||||||
"version": "6.0.0",
|
|
||||||
"rollForward": "latestMinor",
|
|
||||||
"allowPrerelease": false
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace TweetLib.Browser.CEF.Data {
|
namespace TweetLib.Browser.CEF.Data {
|
||||||
abstract class ContextMenuActionRegistry<T> where T : notnull {
|
abstract class ContextMenuActionRegistry<T> {
|
||||||
private readonly Dictionary<T, Action> actions = new ();
|
private readonly Dictionary<T, Action> actions = new ();
|
||||||
|
|
||||||
protected abstract T NextId(int n);
|
protected abstract T NextId(int n);
|
||||||
|
@ -21,7 +21,7 @@ internal bool HasHandler(string url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void Register(string url, Func<TResourceHandler> factory) {
|
private void Register(string url, Func<TResourceHandler> factory) {
|
||||||
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri)) {
|
if (!Uri.TryCreate(url, UriKind.Absolute, out Uri uri)) {
|
||||||
throw new ArgumentException("Resource handler URL must be absolute!");
|
throw new ArgumentException("Resource handler URL must be absolute!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ public bool OnFileDialog(FileDialogType type, IEnumerable<string> acceptFilters,
|
|||||||
};
|
};
|
||||||
|
|
||||||
fileDialogOpener.OpenFile("Open Files", multiple, filters, files => {
|
fileDialogOpener.OpenFile("Open Files", multiple, filters, files => {
|
||||||
string ext = Path.GetExtension(files[0]).ToLower();
|
string ext = Path.GetExtension(files[0])!.ToLower();
|
||||||
callbackAdapter.Continue(callback, Array.FindIndex(supportedExtensions, filter => ParseFileType(filter).Contains(ext)), files);
|
callbackAdapter.Continue(callback, Array.FindIndex(supportedExtensions, filter => ParseFileType(filter).Contains(ext)), files);
|
||||||
callbackAdapter.Dispose(callback);
|
callbackAdapter.Dispose(callback);
|
||||||
}, () => {
|
}, () => {
|
||||||
|
@ -9,7 +9,7 @@ private static (MessageDialogType, string) GetMessageDialogProperties(string tex
|
|||||||
|
|
||||||
int pipe = text.IndexOf('|');
|
int pipe = text.IndexOf('|');
|
||||||
if (pipe != -1) {
|
if (pipe != -1) {
|
||||||
type = text[..pipe] switch {
|
type = text.Substring(0, pipe) switch {
|
||||||
"error" => MessageDialogType.Error,
|
"error" => MessageDialogType.Error,
|
||||||
"warning" => MessageDialogType.Warning,
|
"warning" => MessageDialogType.Warning,
|
||||||
"info" => MessageDialogType.Information,
|
"info" => MessageDialogType.Information,
|
||||||
@ -18,7 +18,7 @@ private static (MessageDialogType, string) GetMessageDialogProperties(string tex
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (type != MessageDialogType.None) {
|
if (type != MessageDialogType.None) {
|
||||||
text = text[(pipe + 1)..];
|
text = text.Substring(pipe + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Platforms>x86;x64</Platforms>
|
<Platforms>x86;x64</Platforms>
|
||||||
<LangVersion>10</LangVersion>
|
<LangVersion>9</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -8,7 +8,7 @@ public static string GetCacheFolder(string storagePath) {
|
|||||||
return Path.Combine(storagePath, "Cache");
|
return Path.Combine(storagePath, "Cache");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommandLineArgs ParseCommandLineArguments(string? argumentString) {
|
public static CommandLineArgs ParseCommandLineArguments(string argumentString) {
|
||||||
CommandLineArgs args = new CommandLineArgs();
|
CommandLineArgs args = new CommandLineArgs();
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(argumentString)) {
|
if (string.IsNullOrWhiteSpace(argumentString)) {
|
||||||
@ -26,8 +26,8 @@ public static CommandLineArgs ParseCommandLineArguments(string? argumentString)
|
|||||||
value = "1";
|
value = "1";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
key = matchValue[..indexEquals].TrimStart('-');
|
key = matchValue.Substring(0, indexEquals).TrimStart('-');
|
||||||
value = matchValue[(indexEquals + 1)..].Trim('"');
|
value = matchValue.Substring(indexEquals + 1).Trim('"');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key.Length != 0) {
|
if (key.Length != 0) {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
namespace TweetLib.Browser.Contexts {
|
namespace TweetLib.Browser.Contexts {
|
||||||
public struct Notification {
|
public struct Notification {
|
||||||
public string? TweetUrl { get; }
|
public string TweetUrl { get; }
|
||||||
public string? QuoteUrl { get; }
|
public string? QuoteUrl { get; }
|
||||||
|
|
||||||
public Notification(string? tweetUrl, string? quoteUrl) {
|
public Notification(string tweetUrl, string? quoteUrl) {
|
||||||
TweetUrl = tweetUrl;
|
TweetUrl = tweetUrl;
|
||||||
QuoteUrl = quoteUrl;
|
QuoteUrl = quoteUrl;
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Platforms>x86;x64</Platforms>
|
<Platforms>x86;x64</Platforms>
|
||||||
<LangVersion>10</LangVersion>
|
<LangVersion>9</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -13,11 +13,13 @@ public static Server CreateServer() {
|
|||||||
|
|
||||||
public static Client CreateClient(string token) {
|
public static Client CreateClient(string token) {
|
||||||
int space = token.IndexOf(' ');
|
int space = token.IndexOf(' ');
|
||||||
return new Client(token[..space], token[(space + 1)..]);
|
return new Client(token.Substring(0, space), token.Substring(space + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly PipeStream pipeIn;
|
private readonly PipeStream pipeIn;
|
||||||
private readonly PipeStream pipeOut;
|
private readonly PipeStream pipeOut;
|
||||||
|
|
||||||
|
private readonly Thread readerThread;
|
||||||
private readonly StreamWriter writerStream;
|
private readonly StreamWriter writerStream;
|
||||||
|
|
||||||
public event EventHandler<PipeReadEventArgs>? DataIn;
|
public event EventHandler<PipeReadEventArgs>? DataIn;
|
||||||
@ -25,21 +27,22 @@ public static Client CreateClient(string token) {
|
|||||||
private DuplexPipe(PipeStream pipeIn, PipeStream pipeOut) {
|
private DuplexPipe(PipeStream pipeIn, PipeStream pipeOut) {
|
||||||
this.pipeIn = pipeIn;
|
this.pipeIn = pipeIn;
|
||||||
this.pipeOut = pipeOut;
|
this.pipeOut = pipeOut;
|
||||||
this.writerStream = new StreamWriter(this.pipeOut);
|
|
||||||
|
|
||||||
new Thread(ReaderThread) { IsBackground = true }.Start();
|
this.readerThread = new Thread(ReaderThread) {
|
||||||
|
IsBackground = true
|
||||||
|
};
|
||||||
|
|
||||||
|
this.readerThread.Start();
|
||||||
|
this.writerStream = new StreamWriter(this.pipeOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReaderThread() {
|
private void ReaderThread() {
|
||||||
using StreamReader read = new StreamReader(pipeIn);
|
using StreamReader read = new StreamReader(pipeIn);
|
||||||
|
string? data;
|
||||||
|
|
||||||
try {
|
while ((data = read.ReadLine()) != null) {
|
||||||
while (read.ReadLine() is {} data) {
|
|
||||||
DataIn?.Invoke(this, new PipeReadEventArgs(data));
|
DataIn?.Invoke(this, new PipeReadEventArgs(data));
|
||||||
}
|
}
|
||||||
} catch (ObjectDisposedException) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write(string key) {
|
public void Write(string key) {
|
||||||
@ -53,6 +56,12 @@ public void Write(string key, string data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose() {
|
public void Dispose() {
|
||||||
|
try {
|
||||||
|
readerThread.Abort();
|
||||||
|
} catch {
|
||||||
|
// /shrug
|
||||||
|
}
|
||||||
|
|
||||||
pipeIn.Dispose();
|
pipeIn.Dispose();
|
||||||
writerStream.Dispose();
|
writerStream.Dispose();
|
||||||
}
|
}
|
||||||
@ -89,8 +98,8 @@ internal PipeReadEventArgs(string line) {
|
|||||||
Data = string.Empty;
|
Data = string.Empty;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Key = line[..separatorIndex];
|
Key = line.Substring(0, separatorIndex);
|
||||||
Data = line[(separatorIndex + 1)..];
|
Data = line.Substring(separatorIndex + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<Platforms>x86</Platforms>
|
<Platforms>x86</Platforms>
|
||||||
<LangVersion>10</LangVersion>
|
<LangVersion>9</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -110,11 +110,11 @@ private static T Validate<T>(T? obj, string name) where T : class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public sealed class AppBuilder {
|
public sealed class AppBuilder {
|
||||||
public IAppSetup? Setup { get; init; }
|
public IAppSetup? Setup { get; set; }
|
||||||
public IAppErrorHandler? ErrorHandler { get; init; }
|
public IAppErrorHandler? ErrorHandler { get; set; }
|
||||||
public IAppSystemHandler? SystemHandler { get; init; }
|
public IAppSystemHandler? SystemHandler { get; set; }
|
||||||
public IAppMessageDialogs? MessageDialogs { get; init; }
|
public IAppMessageDialogs? MessageDialogs { get; set; }
|
||||||
public IAppFileDialogs? FileDialogs { get; init; }
|
public IAppFileDialogs? FileDialogs { get; set; }
|
||||||
|
|
||||||
internal static AppBuilder? Instance { get; private set; }
|
internal static AppBuilder? Instance { get; private set; }
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ public static void LoadResourceRewriteRules(string rules) {
|
|||||||
if (resourceType is ResourceType.Script or ResourceType.Stylesheet && TweetDeckHashes.Count > 0) {
|
if (resourceType is ResourceType.Script or ResourceType.Stylesheet && TweetDeckHashes.Count > 0) {
|
||||||
Match match = TweetDeckResourceUrl.Match(url);
|
Match match = TweetDeckResourceUrl.Match(url);
|
||||||
|
|
||||||
if (match.Success && TweetDeckHashes.TryGetValue($"{match.Groups[1]}.{match.Groups[3]}", out var hash)) {
|
if (match.Success && TweetDeckHashes.TryGetValue($"{match.Groups[1]}.{match.Groups[3]}", out string hash)) {
|
||||||
if (match.Groups[2].Value == hash) {
|
if (match.Groups[2].Value == hash) {
|
||||||
App.Logger.Debug("[RequestHandlerBase] Accepting " + url);
|
App.Logger.Debug("[RequestHandlerBase] Accepting " + url);
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ public void SaveImages(string[] urls, string? author) {
|
|||||||
var settings = new SaveFileDialogSettings {
|
var settings = new SaveFileDialogSettings {
|
||||||
DialogTitle = oneImage ? "Save Image" : "Save Images",
|
DialogTitle = oneImage ? "Save Image" : "Save Images",
|
||||||
OverwritePrompt = oneImage,
|
OverwritePrompt = oneImage,
|
||||||
FileName = qualityIndex == -1 ? filename : $"{author} {Path.ChangeExtension(filename, null)} {firstImageLink[(qualityIndex + 1)..]}".Trim() + ext,
|
FileName = qualityIndex == -1 ? filename : $"{author} {Path.ChangeExtension(filename, null)} {firstImageLink.Substring(qualityIndex + 1)}".Trim() + ext,
|
||||||
Filters = new [] { new FileDialogFilter(oneImage ? "Image" : "Images", string.IsNullOrEmpty(ext) ? Array.Empty<string>() : new [] { ext }) }
|
Filters = new [] { new FileDialogFilter(oneImage ? "Image" : "Images", string.IsNullOrEmpty(ext) ? Array.Empty<string>() : new [] { ext }) }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,9 +56,7 @@ public override void Show(IContextMenuBuilder menu, Context context) {
|
|||||||
menu.AddSeparator();
|
menu.AddSeparator();
|
||||||
|
|
||||||
if (context.Notification is {} notification) {
|
if (context.Notification is {} notification) {
|
||||||
if (!string.IsNullOrEmpty(notification.TweetUrl)) {
|
|
||||||
AddCopyAction(menu, "Copy tweet address", notification.TweetUrl);
|
AddCopyAction(menu, "Copy tweet address", notification.TweetUrl);
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(notification.QuoteUrl)) {
|
if (!string.IsNullOrEmpty(notification.QuoteUrl)) {
|
||||||
AddCopyAction(menu, "Copy quoted tweet address", notification.QuoteUrl!);
|
AddCopyAction(menu, "Copy quoted tweet address", notification.QuoteUrl!);
|
||||||
@ -74,7 +72,7 @@ public override void Dispose() {
|
|||||||
this.browserComponent.PageLoadEnd -= BrowserComponentOnPageLoadEnd;
|
this.browserComponent.PageLoadEnd -= BrowserComponentOnPageLoadEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BrowserComponentOnPageLoadEnd(object? sender, PageLoadEventArgs e) {
|
private void BrowserComponentOnPageLoadEnd(object sender, PageLoadEventArgs e) {
|
||||||
string url = e.Url;
|
string url = e.Url;
|
||||||
|
|
||||||
if (TwitterUrls.IsTweetDeck(url) && url != BlankURL) {
|
if (TwitterUrls.IsTweetDeck(url) && url != BlankURL) {
|
||||||
|
@ -93,7 +93,7 @@ public override int GetHashCode() {
|
|||||||
return Identifier.GetHashCode();
|
return Identifier.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object? obj) {
|
public override bool Equals(object obj) {
|
||||||
return obj is Plugin plugin && plugin.Identifier.Equals(Identifier);
|
return obj is Plugin plugin && plugin.Identifier.Equals(Identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,17 +48,17 @@ internal int GetTokenFromPlugin(Plugin plugin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal Plugin? GetPluginFromToken(int token) {
|
internal Plugin? GetPluginFromToken(int token) {
|
||||||
return tokens.TryGetValue(token, out var plugin) ? plugin : null;
|
return tokens.TryGetValue(token, out Plugin plugin) ? plugin : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event handlers
|
// Event handlers
|
||||||
|
|
||||||
private void manager_Reloaded(object? sender, PluginErrorEventArgs e) {
|
private void manager_Reloaded(object sender, PluginErrorEventArgs e) {
|
||||||
tokens.Clear();
|
tokens.Clear();
|
||||||
fileCache.Clear();
|
fileCache.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Config_PluginChangedState(object? sender, PluginChangedStateEventArgs e) {
|
private void Config_PluginChangedState(object sender, PluginChangedStateEventArgs e) {
|
||||||
if (!e.IsEnabled) {
|
if (!e.IsEnabled) {
|
||||||
int token = GetTokenFromPlugin(e.Plugin);
|
int token = GetTokenFromPlugin(e.Plugin);
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ private string GetFullPathOrThrow(int token, PluginFolder folder, string path) {
|
|||||||
private string ReadFileUnsafe(int token, PluginFolder folder, string path, bool readCached) {
|
private string ReadFileUnsafe(int token, PluginFolder folder, string path, bool readCached) {
|
||||||
string fullPath = GetFullPathOrThrow(token, folder, path);
|
string fullPath = GetFullPathOrThrow(token, folder, path);
|
||||||
|
|
||||||
if (readCached && fileCache.TryGetValue(token, folder, path, out var cachedContents)) {
|
if (readCached && fileCache.TryGetValue(token, folder, path, out string cachedContents)) {
|
||||||
return cachedContents;
|
return cachedContents;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +161,7 @@ public void Clear() {
|
|||||||
cache.Clear();
|
cache.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetValue(int token, PluginFolder folder, string path, [MaybeNullWhen(false)] out string contents) {
|
public bool TryGetValue(int token, PluginFolder folder, string path, out string contents) {
|
||||||
return cache.TryGetValue(token, Key(folder, path), out contents);
|
return cache.TryGetValue(token, Key(folder, path), out contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ public static IEnumerable<Result<Plugin>> AllInFolder(string pluginFolder, strin
|
|||||||
private static Plugin FromFolder(string name, string pathRoot, string pathData, PluginGroup group) {
|
private static Plugin FromFolder(string name, string pathRoot, string pathData, PluginGroup group) {
|
||||||
Plugin.Builder builder = new Plugin.Builder(group, name, pathRoot, pathData);
|
Plugin.Builder builder = new Plugin.Builder(group, name, pathRoot, pathData);
|
||||||
|
|
||||||
foreach (var environment in Directory.EnumerateFiles(pathRoot, "*.js", SearchOption.TopDirectoryOnly).Select(Path.GetFileName).Select(EnvironmentFromFileName!)) {
|
foreach (var environment in Directory.EnumerateFiles(pathRoot, "*.js", SearchOption.TopDirectoryOnly).Select(Path.GetFileName).Select(EnvironmentFromFileName)) {
|
||||||
builder.AddEnvironment(environment);
|
builder.AddEnvironment(environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ private static Plugin FromFolder(string name, string pathRoot, string pathData,
|
|||||||
string currentContents = string.Empty;
|
string currentContents = string.Empty;
|
||||||
|
|
||||||
foreach (string line in File.ReadAllLines(metaFile, Encoding.UTF8).Concat(EndTag).Select(static line => line.TrimEnd()).Where(static line => line.Length > 0)) {
|
foreach (string line in File.ReadAllLines(metaFile, Encoding.UTF8).Concat(EndTag).Select(static line => line.TrimEnd()).Where(static line => line.Length > 0)) {
|
||||||
if (line[0] == '[' && line[^1] == ']') {
|
if (line[0] == '[' && line[line.Length - 1] == ']') {
|
||||||
if (currentTag != null) {
|
if (currentTag != null) {
|
||||||
SetProperty(builder, currentTag, currentContents);
|
SetProperty(builder, currentTag, currentContents);
|
||||||
}
|
}
|
||||||
@ -106,7 +106,7 @@ private static void SetProperty(Plugin.Builder builder, string tag, string value
|
|||||||
builder.ConfigDefault = value;
|
builder.ConfigDefault = value;
|
||||||
break;
|
break;
|
||||||
case "REQUIRES":
|
case "REQUIRES":
|
||||||
builder.RequiredVersion = Version.TryParse(value, out var version) ? version : throw new FormatException($"Invalid required minimum version: {value}");
|
builder.RequiredVersion = Version.TryParse(value, out Version version) ? version : throw new FormatException($"Invalid required minimum version: {value}");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new FormatException($"Invalid metadata tag: {tag}");
|
throw new FormatException($"Invalid metadata tag: {tag}");
|
||||||
|
@ -102,7 +102,7 @@ internal void Execute(PluginEnvironment environment, IScriptExecutor executor) {
|
|||||||
Executed?.Invoke(this, new PluginErrorEventArgs(errors));
|
Executed?.Invoke(this, new PluginErrorEventArgs(errors));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Config_PluginChangedState(object? sender, PluginChangedStateEventArgs e) {
|
private void Config_PluginChangedState(object sender, PluginChangedStateEventArgs e) {
|
||||||
browserExecutor?.RunFunction("TDPF_setPluginState", e.Plugin, e.IsEnabled);
|
browserExecutor?.RunFunction("TDPF_setPluginState", e.Plugin, e.IsEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,12 +71,12 @@ public override void Dispose() {
|
|||||||
App.UserConfiguration.SoundNotificationChanged -= UserConfiguration_SoundNotificationChanged;
|
App.UserConfiguration.SoundNotificationChanged -= UserConfiguration_SoundNotificationChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void browserComponent_BrowserLoaded(object? sender, BrowserLoadedEventArgs e) {
|
private void browserComponent_BrowserLoaded(object sender, BrowserLoadedEventArgs e) {
|
||||||
e.AddDictionaryWords("tweetdeck", "TweetDeck", "tweetduck", "TweetDuck", "TD");
|
e.AddDictionaryWords("tweetdeck", "TweetDeck", "tweetduck", "TweetDuck", "TD");
|
||||||
isBrowserReady = true;
|
isBrowserReady = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void browserComponent_PageLoadStart(object? sender, PageLoadEventArgs e) {
|
private void browserComponent_PageLoadStart(object sender, PageLoadEventArgs e) {
|
||||||
string url = e.Url;
|
string url = e.Url;
|
||||||
|
|
||||||
if (TwitterUrls.IsTweetDeck(url) || (TwitterUrls.IsTwitter(url) && !TwitterUrls.IsTwitterLogin2Factor(url))) {
|
if (TwitterUrls.IsTweetDeck(url) || (TwitterUrls.IsTwitter(url) && !TwitterUrls.IsTwitterLogin2Factor(url))) {
|
||||||
@ -84,7 +84,7 @@ private void browserComponent_PageLoadStart(object? sender, PageLoadEventArgs e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void browserComponent_PageLoadEnd(object? sender, PageLoadEventArgs e) {
|
private void browserComponent_PageLoadEnd(object sender, PageLoadEventArgs e) {
|
||||||
string url = e.Url;
|
string url = e.Url;
|
||||||
|
|
||||||
if (TwitterUrls.IsTweetDeck(url)) {
|
if (TwitterUrls.IsTweetDeck(url)) {
|
||||||
@ -105,7 +105,7 @@ private void browserComponent_PageLoadEnd(object? sender, PageLoadEventArgs e) {
|
|||||||
browserComponent.RunBootstrap("update");
|
browserComponent.RunBootstrap("update");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pluginManager_Reloaded(object? sender, PluginErrorEventArgs e) {
|
private void pluginManager_Reloaded(object sender, PluginErrorEventArgs e) {
|
||||||
if (e.HasErrors) {
|
if (e.HasErrors) {
|
||||||
App.MessageDialogs.Error("Error Loading Plugins", "The following plugins will not be available until the issues are resolved:\n\n" + string.Join("\n\n", e.Errors));
|
App.MessageDialogs.Error("Error Loading Plugins", "The following plugins will not be available until the issues are resolved:\n\n" + string.Join("\n\n", e.Errors));
|
||||||
}
|
}
|
||||||
@ -115,14 +115,14 @@ private void pluginManager_Reloaded(object? sender, PluginErrorEventArgs e) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pluginManager_Executed(object? sender, PluginErrorEventArgs e) {
|
private void pluginManager_Executed(object sender, PluginErrorEventArgs e) {
|
||||||
if (e.HasErrors) {
|
if (e.HasErrors) {
|
||||||
App.MessageDialogs.Error("Error Executing Plugins", "Failed to execute the following plugins:\n\n" + string.Join("\n\n", e.Errors));
|
App.MessageDialogs.Error("Error Executing Plugins", "Failed to execute the following plugins:\n\n" + string.Join("\n\n", e.Errors));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateChecker_CheckFinished(object? sender, UpdateCheckEventArgs e) {
|
private void updateChecker_CheckFinished(object sender, UpdateCheckEventArgs e) {
|
||||||
var updateChecker = (UpdateChecker) sender!;
|
var updateChecker = (UpdateChecker) sender;
|
||||||
|
|
||||||
e.Result.Handle(update => {
|
e.Result.Handle(update => {
|
||||||
string tag = update.VersionTag;
|
string tag = update.VersionTag;
|
||||||
@ -144,7 +144,7 @@ private void updateChecker_CheckFinished(object? sender, UpdateCheckEventArgs e)
|
|||||||
ignoreUpdateCheckError = true;
|
ignoreUpdateCheckError = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UserConfiguration_GeneralEventHandler(object? sender, EventArgs e) {
|
private void UserConfiguration_GeneralEventHandler(object sender, EventArgs e) {
|
||||||
UpdatePropertyObject();
|
UpdatePropertyObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,11 +236,6 @@ private sealed class ResourceRequestHandler : BaseResourceRequestHandler {
|
|||||||
private const string UrlVersionCheck = "/web/dist/version.json";
|
private const string UrlVersionCheck = "/web/dist/version.json";
|
||||||
|
|
||||||
public override RequestHandleResult? Handle(string url, ResourceType resourceType) {
|
public override RequestHandleResult? Handle(string url, ResourceType resourceType) {
|
||||||
var result = base.Handle(url, resourceType);
|
|
||||||
if (result != null) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (resourceType) {
|
switch (resourceType) {
|
||||||
case ResourceType.MainFrame when url.EndsWithOrdinal("://twitter.com/"):
|
case ResourceType.MainFrame when url.EndsWithOrdinal("://twitter.com/"):
|
||||||
return new RequestHandleResult.Redirect(TwitterUrls.TweetDeck); // redirect plain twitter.com requests, fixes bugs with login 2FA
|
return new RequestHandleResult.Redirect(TwitterUrls.TweetDeck); // redirect plain twitter.com requests, fixes bugs with login 2FA
|
||||||
@ -261,7 +256,7 @@ private sealed class ResourceRequestHandler : BaseResourceRequestHandler {
|
|||||||
return new RequestHandleResult.Redirect(url.Replace("include_entities=1", "include_entities=1&include_ext_has_nft_avatar=1"));
|
return new RequestHandleResult.Redirect(url.Replace("include_entities=1", "include_entities=1&include_ext_has_nft_avatar=1"));
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return base.Handle(url, resourceType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,15 +24,15 @@ public void SetLink(string type, string? url) {
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "link":
|
case "link":
|
||||||
Link = new Link(url, url);
|
Link = new Link(url!, url!);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "image":
|
case "image":
|
||||||
Media = new Media(Type.Image, TwitterUrls.GetMediaLink(url, App.UserConfiguration.TwitterImageQuality));
|
Media = new Media(Type.Image, TwitterUrls.GetMediaLink(url!, App.UserConfiguration.TwitterImageQuality));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "video":
|
case "video":
|
||||||
Media = new Media(Type.Video, url);
|
Media = new Media(Type.Video, url!);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ public static bool TryParse(string url, out ImageUrl obj) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
string originalUrl = url[..question];
|
string originalUrl = url.Substring(0, question);
|
||||||
|
|
||||||
obj = new ImageUrl(Path.HasExtension(originalUrl) ? originalUrl : originalUrl + imageExtension, imageQuality);
|
obj = new ImageUrl(Path.HasExtension(originalUrl) ? originalUrl : originalUrl + imageExtension, imageQuality);
|
||||||
return true;
|
return true;
|
||||||
|
@ -49,11 +49,11 @@ public enum UrlType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static UrlType Check(string url) {
|
public static UrlType Check(string url) {
|
||||||
if (url.Contains('"')) {
|
if (url.Contains("\"")) {
|
||||||
return UrlType.Invalid;
|
return UrlType.Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Uri.TryCreate(url, UriKind.Absolute, out var uri)) {
|
if (Uri.TryCreate(url, UriKind.Absolute, out Uri uri)) {
|
||||||
string scheme = uri.Scheme;
|
string scheme = uri.Scheme;
|
||||||
|
|
||||||
if (scheme == Uri.UriSchemeHttps || scheme == Uri.UriSchemeHttp || scheme == Uri.UriSchemeFtp || scheme == Uri.UriSchemeMailto) {
|
if (scheme == Uri.UriSchemeHttps || scheme == Uri.UriSchemeHttp || scheme == Uri.UriSchemeFtp || scheme == Uri.UriSchemeMailto) {
|
||||||
|
@ -16,7 +16,7 @@ static ConfigManager() {
|
|||||||
ConverterRegistry.Register(typeof(WindowState), new BasicTypeConverter<WindowState> {
|
ConverterRegistry.Register(typeof(WindowState), new BasicTypeConverter<WindowState> {
|
||||||
ConvertToString = static value => $"{(value.IsMaximized ? 'M' : '_')}{value.Bounds.X} {value.Bounds.Y} {value.Bounds.Width} {value.Bounds.Height}",
|
ConvertToString = static value => $"{(value.IsMaximized ? 'M' : '_')}{value.Bounds.X} {value.Bounds.Y} {value.Bounds.Width} {value.Bounds.Height}",
|
||||||
ConvertToObject = static value => {
|
ConvertToObject = static value => {
|
||||||
int[] elements = StringUtils.ParseInts(value[1..], ' ');
|
int[] elements = StringUtils.ParseInts(value.Substring(1), ' ');
|
||||||
|
|
||||||
return new WindowState {
|
return new WindowState {
|
||||||
Bounds = new Rectangle(elements[0], elements[1], elements[2], elements[3]),
|
Bounds = new Rectangle(elements[0], elements[1], elements[2], elements[3]),
|
||||||
|
@ -43,7 +43,7 @@ private bool Log(string level, string message) {
|
|||||||
build.Append("Please, report all issues to: ").Append(Lib.IssueTrackerUrl).Append("\r\n\r\n");
|
build.Append("Please, report all issues to: ").Append(Lib.IssueTrackerUrl).Append("\r\n\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
build.Append('[').Append(DateTime.Now.ToString("G", Lib.Culture)).Append("] ").Append(level).Append("\r\n");
|
build.Append("[").Append(DateTime.Now.ToString("G", Lib.Culture)).Append("] ").Append(level).Append("\r\n");
|
||||||
build.Append(message).Append("\r\n\r\n");
|
build.Append(message).Append("\r\n\r\n");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -37,7 +37,7 @@ public void Dispose() {
|
|||||||
InteractionManager.Dispose();
|
InteractionManager.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void timer_Elapsed(object? sender, ElapsedEventArgs e) {
|
private void timer_Elapsed(object sender, ElapsedEventArgs e) {
|
||||||
Check(false);
|
Check(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ public void ClearUpdate() {
|
|||||||
nextUpdate = null;
|
nextUpdate = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updates_CheckFinished(object? sender, UpdateCheckEventArgs e) {
|
private void updates_CheckFinished(object sender, UpdateCheckEventArgs e) {
|
||||||
UpdateInfo? foundUpdate = e.Result.HasValue ? e.Result.Value : null;
|
UpdateInfo? foundUpdate = e.Result.HasValue ? e.Result.Value : null;
|
||||||
|
|
||||||
if (nextUpdate != null && !nextUpdate.Equals(foundUpdate)) {
|
if (nextUpdate != null && !nextUpdate.Equals(foundUpdate)) {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Platforms>x86;x64</Platforms>
|
<Platforms>x86;x64</Platforms>
|
||||||
<LangVersion>10</LangVersion>
|
<LangVersion>9</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -57,7 +57,7 @@ public void SetValue(string key, string value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public string? GetValue(string key) {
|
public string? GetValue(string key) {
|
||||||
return values.TryGetValue(key.ToLower(), out var val) ? val : null;
|
return values.TryGetValue(key.ToLower(), out string val) ? val : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveValue(string key) {
|
public void RemoveValue(string key) {
|
||||||
|
@ -11,7 +11,7 @@ namespace TweetLib.Utils.Collections {
|
|||||||
/// <typeparam name="V">The type of the values.</typeparam>
|
/// <typeparam name="V">The type of the values.</typeparam>
|
||||||
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
|
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
|
||||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||||
public sealed class TwoKeyDictionary<K1, K2, V> where K1 : notnull where K2 : notnull {
|
public sealed class TwoKeyDictionary<K1, K2, V> {
|
||||||
private readonly Dictionary<K1, Dictionary<K2, V>> dict;
|
private readonly Dictionary<K1, Dictionary<K2, V>> dict;
|
||||||
private readonly int innerCapacity;
|
private readonly int innerCapacity;
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ public TwoKeyDictionary(int outerCapacity, int innerCapacity) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set {
|
set {
|
||||||
if (!dict.TryGetValue(outerKey, out Dictionary<K2, V>? innerDict)) {
|
if (!dict.TryGetValue(outerKey, out Dictionary<K2, V> innerDict)) {
|
||||||
dict.Add(outerKey, innerDict = new Dictionary<K2, V>(innerCapacity));
|
dict.Add(outerKey, innerDict = new Dictionary<K2, V>(innerCapacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ public IEnumerable<V> InnerValues {
|
|||||||
/// Throws if the key pair already exists.
|
/// Throws if the key pair already exists.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Add(K1 outerKey, K2 innerKey, V value) {
|
public void Add(K1 outerKey, K2 innerKey, V value) {
|
||||||
if (!dict.TryGetValue(outerKey, out Dictionary<K2, V>? innerDict)) {
|
if (!dict.TryGetValue(outerKey, out Dictionary<K2, V> innerDict)) {
|
||||||
dict.Add(outerKey, innerDict = new Dictionary<K2, V>(innerCapacity));
|
dict.Add(outerKey, innerDict = new Dictionary<K2, V>(innerCapacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ public bool Contains(K1 outerKey) {
|
|||||||
/// Determines whether the dictionary contains the key pair.
|
/// Determines whether the dictionary contains the key pair.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Contains(K1 outerKey, K2 innerKey) {
|
public bool Contains(K1 outerKey, K2 innerKey) {
|
||||||
return dict.TryGetValue(outerKey, out Dictionary<K2, V>? innerDict) && innerDict.ContainsKey(innerKey);
|
return dict.TryGetValue(outerKey, out Dictionary<K2, V> innerDict) && innerDict.ContainsKey(innerKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -122,8 +122,8 @@ public int Count(K1 outerKey) {
|
|||||||
/// Gets the value associated with the key pair.
|
/// Gets the value associated with the key pair.
|
||||||
/// Returns true if the key pair was present.
|
/// Returns true if the key pair was present.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TryGetValue(K1 outerKey, K2 innerKey, [MaybeNullWhen(false)] out V value) {
|
public bool TryGetValue(K1 outerKey, K2 innerKey, out V value) {
|
||||||
if (dict.TryGetValue(outerKey, out Dictionary<K2, V>? innerDict)) {
|
if (dict.TryGetValue(outerKey, out Dictionary<K2, V> innerDict)) {
|
||||||
return innerDict.TryGetValue(innerKey, out value);
|
return innerDict.TryGetValue(innerKey, out value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -145,7 +145,7 @@ public bool Remove(K1 outerKey) {
|
|||||||
/// Returns true if the key pair was present.
|
/// Returns true if the key pair was present.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Remove(K1 outerKey, K2 innerKey) {
|
public bool Remove(K1 outerKey, K2 innerKey) {
|
||||||
if (dict.TryGetValue(outerKey, out Dictionary<K2, V>? innerDict) && innerDict.Remove(innerKey)) {
|
if (dict.TryGetValue(outerKey, out Dictionary<K2, V> innerDict) && innerDict.Remove(innerKey)) {
|
||||||
if (innerDict.Count == 0) {
|
if (innerDict.Count == 0) {
|
||||||
dict.Remove(outerKey);
|
dict.Remove(outerKey);
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
namespace TweetLib.Utils.Dialogs {
|
namespace TweetLib.Utils.Dialogs {
|
||||||
public sealed class SaveFileDialogSettings {
|
public sealed class SaveFileDialogSettings {
|
||||||
public string DialogTitle { get; init; } = "Save File";
|
public string DialogTitle { get; set; } = "Save File";
|
||||||
public bool OverwritePrompt { get; init; } = true;
|
public bool OverwritePrompt { get; set; } = true;
|
||||||
public string? FileName { get; init; }
|
public string? FileName { get; set; }
|
||||||
public IReadOnlyList<FileDialogFilter>? Filters { get; init; }
|
public IReadOnlyList<FileDialogFilter>? Filters { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ public Language(string code, string? alt = null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object? obj) {
|
public override bool Equals(object obj) {
|
||||||
return obj is Language other && Code.Equals(other.Code, StringComparison.OrdinalIgnoreCase);
|
return obj is Language other && Code.Equals(other.Code, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,8 +38,8 @@ public override string ToString() {
|
|||||||
return cultureInfo.DisplayName == cultureInfo.NativeName ? capitalizedName : $"{capitalizedName}, {cultureInfo.DisplayName}";
|
return cultureInfo.DisplayName == cultureInfo.NativeName ? capitalizedName : $"{capitalizedName}, {cultureInfo.DisplayName}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CompareTo(Language? other) {
|
public int CompareTo(Language other) {
|
||||||
return string.Compare(Name, other?.Name, false, CultureInfo.InvariantCulture);
|
return string.Compare(Name, other.Name, false, CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,7 @@ public sealed class Entry {
|
|||||||
public string[] KeyValue {
|
public string[] KeyValue {
|
||||||
get {
|
get {
|
||||||
int index = Identifier.IndexOf(KeySeparator);
|
int index = Identifier.IndexOf(KeySeparator);
|
||||||
return index == -1 ? StringUtils.EmptyArray : Identifier[(index + 1)..].Split(KeySeparator);
|
return index == -1 ? StringUtils.EmptyArray : Identifier.Substring(index + 1).Split(KeySeparator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
namespace TweetLib.Utils.Serialization.Converters {
|
namespace TweetLib.Utils.Serialization.Converters {
|
||||||
public sealed class BasicTypeConverter<T> : ITypeConverter {
|
public sealed class BasicTypeConverter<T> : ITypeConverter {
|
||||||
public Func<T, string>? ConvertToString { get; init; }
|
public Func<T, string>? ConvertToString { get; set; }
|
||||||
public Func<string, T>? ConvertToObject { get; init; }
|
public Func<string, T>? ConvertToObject { get; set; }
|
||||||
|
|
||||||
bool ITypeConverter.TryWriteType(Type type, object? value, out string? converted) {
|
bool ITypeConverter.TryWriteType(Type type, object value, out string? converted) {
|
||||||
try {
|
try {
|
||||||
converted = ConvertToString!((T) value!);
|
converted = ConvertToString!((T) value);
|
||||||
return true;
|
return true;
|
||||||
} catch {
|
} catch {
|
||||||
converted = null;
|
converted = null;
|
||||||
|
@ -6,17 +6,18 @@ sealed class ClrTypeConverter : ITypeConverter {
|
|||||||
|
|
||||||
private ClrTypeConverter() {}
|
private ClrTypeConverter() {}
|
||||||
|
|
||||||
bool ITypeConverter.TryWriteType(Type type, object? value, out string? converted) {
|
bool ITypeConverter.TryWriteType(Type type, object value, out string? converted) {
|
||||||
switch (Type.GetTypeCode(type)) {
|
switch (Type.GetTypeCode(type)) {
|
||||||
case TypeCode.Boolean:
|
case TypeCode.Boolean:
|
||||||
converted = value!.ToString();
|
converted = value.ToString();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case TypeCode.Int32:
|
case TypeCode.Int32:
|
||||||
converted = ((int) value!).ToString(); // cast required for enums
|
converted = ((int) value).ToString(); // cast required for enums
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case TypeCode.String:
|
case TypeCode.String:
|
||||||
|
// ReSharper disable once ConstantConditionalAccessQualifier
|
||||||
converted = value?.ToString();
|
converted = value?.ToString();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace TweetLib.Utils.Serialization {
|
namespace TweetLib.Utils.Serialization {
|
||||||
public interface ITypeConverter {
|
public interface ITypeConverter {
|
||||||
bool TryWriteType(Type type, object? value, out string? converted);
|
bool TryWriteType(Type type, object value, out string? converted);
|
||||||
bool TryReadType(Type type, string value, out object? converted);
|
bool TryReadType(Type type, string value, out object? converted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ private static string UnescapeStream(StreamReader reader) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
build.Append(data[index..nextIndex]);
|
build.Append(data.Substring(index, nextIndex - index));
|
||||||
|
|
||||||
char next = data[nextIndex + 1];
|
char next = data[nextIndex + 1];
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ private static string UnescapeStream(StreamReader reader) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return build.Append(data[index..]).ToString();
|
return build.Append(data.Substring(index)).ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly TypeConverterRegistry converterRegistry;
|
private readonly TypeConverterRegistry converterRegistry;
|
||||||
@ -114,7 +114,7 @@ public void Read(string file, T obj) {
|
|||||||
int nextPos = contents.IndexOf(NewLineReal, currentPos);
|
int nextPos = contents.IndexOf(NewLineReal, currentPos);
|
||||||
|
|
||||||
if (nextPos == -1) {
|
if (nextPos == -1) {
|
||||||
line = contents[currentPos..];
|
line = contents.Substring(currentPos);
|
||||||
currentPos = -1;
|
currentPos = -1;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(line)) {
|
if (string.IsNullOrEmpty(line)) {
|
||||||
@ -133,10 +133,10 @@ public void Read(string file, T obj) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
string property = line[..space];
|
string property = line.Substring(0, space);
|
||||||
string value = UnescapeLine(line[(space + 1)..]);
|
string value = UnescapeLine(line.Substring(space + 1));
|
||||||
|
|
||||||
if (props.TryGetValue(property, out var info)) {
|
if (props.TryGetValue(property, out PropertyInfo info)) {
|
||||||
var type = info.PropertyType;
|
var type = info.PropertyType;
|
||||||
var converter = converterRegistry.TryGet(type) ?? ClrTypeConverter.Instance;
|
var converter = converterRegistry.TryGet(type) ?? ClrTypeConverter.Instance;
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using TweetLib.Utils.Static;
|
using TweetLib.Utils.Static;
|
||||||
@ -90,6 +91,7 @@ public UnlockResult Unlock() {
|
|||||||
return UnlockResult.Success;
|
return UnlockResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("ReSharper", "PossibleNullReferenceException")]
|
||||||
private LockResult DetermineLockingProcessOrFail(Exception originalException) {
|
private LockResult DetermineLockingProcessOrFail(Exception originalException) {
|
||||||
try {
|
try {
|
||||||
int pid;
|
int pid;
|
||||||
@ -108,7 +110,7 @@ private LockResult DetermineLockingProcessOrFail(Exception originalException) {
|
|||||||
var foundProcess = Process.GetProcessById(pid);
|
var foundProcess = Process.GetProcessById(pid);
|
||||||
using var currentProcess = Process.GetCurrentProcess();
|
using var currentProcess = Process.GetCurrentProcess();
|
||||||
|
|
||||||
if (currentProcess.MainModule!.FileVersionInfo.InternalName == foundProcess.MainModule!.FileVersionInfo.InternalName) {
|
if (currentProcess.MainModule.FileVersionInfo.InternalName == foundProcess.MainModule.FileVersionInfo.InternalName) {
|
||||||
return new LockResult.HasProcess(foundProcess);
|
return new LockResult.HasProcess(foundProcess);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -40,7 +40,7 @@ public static (string before, string after)? SplitInTwo(string str, char search,
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (str[..index], str[(index + 1)..]);
|
return (str.Substring(0, index), str.Substring(index + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -49,7 +49,7 @@ public static (string before, string after)? SplitInTwo(string str, char search,
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static string ExtractBefore(string str, char search, int startIndex = 0) {
|
public static string ExtractBefore(string str, char search, int startIndex = 0) {
|
||||||
int index = str.IndexOf(search, startIndex);
|
int index = str.IndexOf(search, startIndex);
|
||||||
return index == -1 ? str : str[..index];
|
return index == -1 ? str : str.Substring(0, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -10,12 +10,10 @@ public static class WebUtils {
|
|||||||
private static bool hasMicrosoftBeenBroughtTo2008Yet;
|
private static bool hasMicrosoftBeenBroughtTo2008Yet;
|
||||||
private static bool hasSystemProxyBeenEnabled;
|
private static bool hasSystemProxyBeenEnabled;
|
||||||
|
|
||||||
private static void EnsureModernTLS() {
|
private static void EnsureTLS12() {
|
||||||
if (!hasMicrosoftBeenBroughtTo2008Yet) {
|
if (!hasMicrosoftBeenBroughtTo2008Yet) {
|
||||||
#pragma warning disable CS0618
|
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
|
||||||
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;
|
|
||||||
ServicePointManager.SecurityProtocol &= ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11);
|
ServicePointManager.SecurityProtocol &= ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11);
|
||||||
#pragma warning restore CS0618
|
|
||||||
hasMicrosoftBeenBroughtTo2008Yet = true;
|
hasMicrosoftBeenBroughtTo2008Yet = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -30,7 +28,7 @@ public static void EnableSystemProxy() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static WebClient NewClient(string? userAgent = null) {
|
public static WebClient NewClient(string? userAgent = null) {
|
||||||
EnsureModernTLS();
|
EnsureTLS12();
|
||||||
|
|
||||||
WebClient client = new WebClient();
|
WebClient client = new WebClient();
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Platforms>x86;x64</Platforms>
|
<Platforms>x86;x64</Platforms>
|
||||||
<LangVersion>10</LangVersion>
|
<LangVersion>9</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net472</TargetFramework>
|
||||||
<Platforms>x86</Platforms>
|
<Platforms>x86</Platforms>
|
||||||
<RuntimeIdentifiers>win7-x86;linux-x64</RuntimeIdentifiers>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -47,7 +47,7 @@ module RegexAccount =
|
|||||||
Assert.True(isMatch("https://twitter.com/" + name))
|
Assert.True(isMatch("https://twitter.com/" + name))
|
||||||
|
|
||||||
module Match =
|
module Match =
|
||||||
let extract str = TwitterUrls.RegexAccount.Match(str).Groups[1].Value
|
let extract str = TwitterUrls.RegexAccount.Match(str).Groups.[1].Value
|
||||||
|
|
||||||
[<Fact>]
|
[<Fact>]
|
||||||
let ``extracts account name from simple URL`` () =
|
let ``extracts account name from simple URL`` () =
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net472</TargetFramework>
|
||||||
<Platforms>x86</Platforms>
|
<Platforms>x86</Platforms>
|
||||||
<RuntimeIdentifiers>win7-x86;linux-x64</RuntimeIdentifiers>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user