From edb86303ad5aecd43346d84b0f0b104acf7a3385 Mon Sep 17 00:00:00 2001
From: ScrubN <72096833+ScrubN@users.noreply.github.com>
Date: Sun, 26 May 2024 15:46:28 -0400
Subject: [PATCH 1/9] Bump SDK from .NET 6 to .NET 8
---
.github/workflows/build-pr.yml | 24 +++++++++----------
.github/workflows/build.yml | 24 +++++++++----------
.../TwitchDownloaderCLI.Tests.csproj | 2 +-
.../Properties/PublishProfiles/Linux.pubxml | 5 ++--
.../PublishProfiles/LinuxAlpine.pubxml | 5 ++--
.../PublishProfiles/LinuxArm.pubxml | 5 ++--
.../PublishProfiles/LinuxArm64.pubxml | 5 ++--
.../Properties/PublishProfiles/MacOS.pubxml | 5 ++--
.../PublishProfiles/MacOSArm64.pubxml | 5 ++--
.../Properties/PublishProfiles/Windows.pubxml | 5 ++--
.../TwitchDownloaderCLI.csproj | 2 +-
.../TwitchDownloaderCore.Tests.csproj | 2 +-
.../TwitchDownloaderCore.csproj | 2 +-
.../Properties/PublishProfiles/Windows.pubxml | 4 ++--
.../TwitchDownloaderWPF.csproj | 2 +-
15 files changed, 52 insertions(+), 45 deletions(-)
diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml
index 7f00e89a..4ec706b3 100644
--- a/.github/workflows/build-pr.yml
+++ b/.github/workflows/build-pr.yml
@@ -18,7 +18,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 6.0.x
+ dotnet-version: 8.0.x
- name: Restore Dependencies
run: dotnet restore TwitchDownloaderWPF
- name: Build Windows GUI
@@ -35,12 +35,12 @@ jobs:
file-name: ffmpeg.zip
- name: Bundle FFmpeg
- run: tar xfz ffmpeg.zip --strip-components=1; copy bin/ffmpeg.exe TwitchDownloaderWPF/bin/Release/net6.0-windows/publish/win-x64/ffmpeg.exe
+ run: tar xfz ffmpeg.zip --strip-components=1; copy bin/ffmpeg.exe TwitchDownloaderWPF/bin/Release/net8.0-windows/publish/win-x64/ffmpeg.exe
- name: Zip Windows GUI
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderWPF/bin/Release/net6.0-windows/publish/win-x64"
+ files: "TwitchDownloaderWPF/bin/Release/net8.0-windows/publish/win-x64"
dest: TwitchDownloaderGUI-Windows-x64.zip
- name: Upload Windows GUI Artifact Asset
@@ -57,7 +57,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 6.0.x
+ dotnet-version: 8.0.x
- name: Restore Dependencies
run: dotnet restore TwitchDownloaderCLI
- name: Build Windows CLI
@@ -74,31 +74,31 @@ jobs:
- name: Zip Windows CLI
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderCLI/bin/Release/net6.0/publish/Windows"
+ files: "TwitchDownloaderCLI/bin/Release/net8.0/publish/Windows"
dest: TwitchDownloaderCLI-Windows-x64.zip
- name: Zip Linux CLI
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderCLI/bin/Release/net6.0/publish/Linux"
+ files: "TwitchDownloaderCLI/bin/Release/net8.0/publish/Linux"
dest: TwitchDownloaderCLI-Linux-x64.zip
- name: Zip LinuxAlpine CLI
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderCLI/bin/Release/net6.0/publish/LinuxAlpine"
+ files: "TwitchDownloaderCLI/bin/Release/net8.0/publish/LinuxAlpine"
dest: TwitchDownloaderCLI-LinuxAlpine-x64.zip
- name: Zip LinuxArm CLI
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderCLI/bin/Release/net6.0/publish/LinuxArm"
+ files: "TwitchDownloaderCLI/bin/Release/net8.0/publish/LinuxArm"
dest: TwitchDownloaderCLI-LinuxArm.zip
- name: Zip LinuxArm64 CLI
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderCLI/bin/Release/net6.0/publish/LinuxArm64"
+ files: "TwitchDownloaderCLI/bin/Release/net8.0/publish/LinuxArm64"
dest: TwitchDownloaderCLI-LinuxArm64.zip
- name: Upload Windows CLI Artifact Asset
@@ -139,7 +139,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 6.0.x
+ dotnet-version: 8.0.x
- name: Restore Dependencies
run: dotnet restore TwitchDownloaderCLI
- name: Build MacOS CLI
@@ -150,13 +150,13 @@ jobs:
- name: Zip MacOS CLI
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderCLI/bin/Release/net6.0/publish/MacOS"
+ files: "TwitchDownloaderCLI/bin/Release/net8.0/publish/MacOS"
dest: TwitchDownloaderCLI-MacOS-x64.zip
- name: Zip MacOSArm64 CLI
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderCLI/bin/Release/net6.0/publish/MacOSArm64"
+ files: "TwitchDownloaderCLI/bin/Release/net8.0/publish/MacOSArm64"
dest: TwitchDownloaderCLI-MacOSArm64.zip
- name: Upload MacOS CLI Artifact Asset
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 66d76aa0..dbd5ad6d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -43,7 +43,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 6.0.x
+ dotnet-version: 8.0.x
- name: Restore Dependencies
run: dotnet restore TwitchDownloaderWPF
- name: Build Windows GUI
@@ -60,12 +60,12 @@ jobs:
file-name: ffmpeg.zip
- name: Bundle FFmpeg
- run: tar xfz ffmpeg.zip --strip-components=1; copy bin/ffmpeg.exe TwitchDownloaderWPF/bin/Release/net6.0-windows/publish/win-x64/ffmpeg.exe
+ run: tar xfz ffmpeg.zip --strip-components=1; copy bin/ffmpeg.exe TwitchDownloaderWPF/bin/Release/net8.0-windows/publish/win-x64/ffmpeg.exe
- name: Zip Windows GUI Release Asset
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderWPF/bin/Release/net6.0-windows/publish/win-x64"
+ files: "TwitchDownloaderWPF/bin/Release/net8.0-windows/publish/win-x64"
dest: TwitchDownloaderGUI-${{ github.event.inputs.release_tag }}-Windows-x64.zip
- name: Download URL
@@ -98,7 +98,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 6.0.x
+ dotnet-version: 8.0.x
- name: Restore Dependencies
run: dotnet restore TwitchDownloaderCLI
- name: Build Windows CLI
@@ -115,31 +115,31 @@ jobs:
- name: Zip Windows CLI
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderCLI/bin/Release/net6.0/publish/Windows"
+ files: "TwitchDownloaderCLI/bin/Release/net8.0/publish/Windows"
dest: TwitchDownloaderCLI-${{ github.event.inputs.release_tag }}-Windows-x64.zip
- name: Zip Linux CLI
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderCLI/bin/Release/net6.0/publish/Linux"
+ files: "TwitchDownloaderCLI/bin/Release/net8.0/publish/Linux"
dest: TwitchDownloaderCLI-${{ github.event.inputs.release_tag }}-Linux-x64.zip
- name: Zip LinuxAlpine CLI
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderCLI/bin/Release/net6.0/publish/LinuxAlpine"
+ files: "TwitchDownloaderCLI/bin/Release/net8.0/publish/LinuxAlpine"
dest: TwitchDownloaderCLI-${{ github.event.inputs.release_tag }}-LinuxAlpine-x64.zip
- name: Zip LinuxArm CLI
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderCLI/bin/Release/net6.0/publish/LinuxArm"
+ files: "TwitchDownloaderCLI/bin/Release/net8.0/publish/LinuxArm"
dest: TwitchDownloaderCLI-${{ github.event.inputs.release_tag }}-LinuxArm.zip
- name: Zip LinuxArm64 CLI
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderCLI/bin/Release/net6.0/publish/LinuxArm64"
+ files: "TwitchDownloaderCLI/bin/Release/net8.0/publish/LinuxArm64"
dest: TwitchDownloaderCLI-${{ github.event.inputs.release_tag }}-LinuxArm64.zip
- name: Download URL
@@ -211,7 +211,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 6.0.x
+ dotnet-version: 8.0.x
- name: Restore Dependencies
run: dotnet restore TwitchDownloaderCLI
- name: Build MacOS CLI
@@ -222,13 +222,13 @@ jobs:
- name: Zip MacOS CLI
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderCLI/bin/Release/net6.0/publish/MacOS"
+ files: "TwitchDownloaderCLI/bin/Release/net8.0/publish/MacOS"
dest: TwitchDownloaderCLI-${{ github.event.inputs.release_tag }}-MacOS-x64.zip
- name: Zip MacOSArm64 CLI
uses: vimtor/action-zip@v1.1
with:
- files: "TwitchDownloaderCLI/bin/Release/net6.0/publish/MacOSArm64"
+ files: "TwitchDownloaderCLI/bin/Release/net8.0/publish/MacOSArm64"
dest: TwitchDownloaderCLI-${{ github.event.inputs.release_tag }}-MacOSArm64.zip
- name: Download URL
diff --git a/TwitchDownloaderCLI.Tests/TwitchDownloaderCLI.Tests.csproj b/TwitchDownloaderCLI.Tests/TwitchDownloaderCLI.Tests.csproj
index a0b77556..9de12c84 100644
--- a/TwitchDownloaderCLI.Tests/TwitchDownloaderCLI.Tests.csproj
+++ b/TwitchDownloaderCLI.Tests/TwitchDownloaderCLI.Tests.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net8.0
enable
enable
diff --git a/TwitchDownloaderCLI/Properties/PublishProfiles/Linux.pubxml b/TwitchDownloaderCLI/Properties/PublishProfiles/Linux.pubxml
index 2fea392c..b3d93c18 100644
--- a/TwitchDownloaderCLI/Properties/PublishProfiles/Linux.pubxml
+++ b/TwitchDownloaderCLI/Properties/PublishProfiles/Linux.pubxml
@@ -7,12 +7,13 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
FileSystem
Release
Any CPU
- net6.0
- bin\Release\net6.0\publish\Linux
+ net8.0
+ bin\Release\net8.0\publish\Linux
linux-x64
true
True
True
+ partial
true
\ No newline at end of file
diff --git a/TwitchDownloaderCLI/Properties/PublishProfiles/LinuxAlpine.pubxml b/TwitchDownloaderCLI/Properties/PublishProfiles/LinuxAlpine.pubxml
index 1adbee69..36eb462c 100644
--- a/TwitchDownloaderCLI/Properties/PublishProfiles/LinuxAlpine.pubxml
+++ b/TwitchDownloaderCLI/Properties/PublishProfiles/LinuxAlpine.pubxml
@@ -6,14 +6,15 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
Release
x64
- bin\Release\net6.0\publish\LinuxAlpine
+ bin\Release\net8.0\publish\LinuxAlpine
FileSystem
- net6.0
+ net8.0
linux-musl-x64
true
True
False
True
+ partial
true
\ No newline at end of file
diff --git a/TwitchDownloaderCLI/Properties/PublishProfiles/LinuxArm.pubxml b/TwitchDownloaderCLI/Properties/PublishProfiles/LinuxArm.pubxml
index e424a191..37bd5e6d 100644
--- a/TwitchDownloaderCLI/Properties/PublishProfiles/LinuxArm.pubxml
+++ b/TwitchDownloaderCLI/Properties/PublishProfiles/LinuxArm.pubxml
@@ -6,13 +6,14 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
Release
Any CPU
- bin\Release\net6.0\publish\LinuxArm
+ bin\Release\net8.0\publish\LinuxArm
FileSystem
- net6.0
+ net8.0
linux-arm
true
True
True
+ partial
true
\ No newline at end of file
diff --git a/TwitchDownloaderCLI/Properties/PublishProfiles/LinuxArm64.pubxml b/TwitchDownloaderCLI/Properties/PublishProfiles/LinuxArm64.pubxml
index ce762606..e951ced2 100644
--- a/TwitchDownloaderCLI/Properties/PublishProfiles/LinuxArm64.pubxml
+++ b/TwitchDownloaderCLI/Properties/PublishProfiles/LinuxArm64.pubxml
@@ -7,12 +7,13 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
FileSystem
Release
Any CPU
- net6.0
- bin\Release\net6.0\publish\LinuxArm64
+ net8.0
+ bin\Release\net8.0\publish\LinuxArm64
linux-arm64
true
True
True
+ partial
true
diff --git a/TwitchDownloaderCLI/Properties/PublishProfiles/MacOS.pubxml b/TwitchDownloaderCLI/Properties/PublishProfiles/MacOS.pubxml
index 789cc72a..68f614d9 100644
--- a/TwitchDownloaderCLI/Properties/PublishProfiles/MacOS.pubxml
+++ b/TwitchDownloaderCLI/Properties/PublishProfiles/MacOS.pubxml
@@ -6,13 +6,14 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
Release
Any CPU
- bin\Release\net6.0\publish\MacOS
+ bin\Release\net8.0\publish\MacOS
FileSystem
- net6.0
+ net8.0
osx-x64
true
True
True
+ partial
true
true
diff --git a/TwitchDownloaderCLI/Properties/PublishProfiles/MacOSArm64.pubxml b/TwitchDownloaderCLI/Properties/PublishProfiles/MacOSArm64.pubxml
index 84087d4b..67b73c50 100644
--- a/TwitchDownloaderCLI/Properties/PublishProfiles/MacOSArm64.pubxml
+++ b/TwitchDownloaderCLI/Properties/PublishProfiles/MacOSArm64.pubxml
@@ -6,13 +6,14 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
Release
Any CPU
- bin\Release\net6.0\publish\MacOSArm64
+ bin\Release\net8.0\publish\MacOSArm64
FileSystem
- net6.0
+ net8.0
osx-arm64
true
True
True
+ partial
true
true
diff --git a/TwitchDownloaderCLI/Properties/PublishProfiles/Windows.pubxml b/TwitchDownloaderCLI/Properties/PublishProfiles/Windows.pubxml
index 94566a3c..6cc91ee5 100644
--- a/TwitchDownloaderCLI/Properties/PublishProfiles/Windows.pubxml
+++ b/TwitchDownloaderCLI/Properties/PublishProfiles/Windows.pubxml
@@ -6,14 +6,15 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
Release
x64
- bin\Release\net6.0\publish\Windows
+ bin\Release\net8.0\publish\Windows
FileSystem
- net6.0
+ net8.0
win-x64
true
True
False
True
+ partial
true
\ No newline at end of file
diff --git a/TwitchDownloaderCLI/TwitchDownloaderCLI.csproj b/TwitchDownloaderCLI/TwitchDownloaderCLI.csproj
index 19138245..15da5bab 100644
--- a/TwitchDownloaderCLI/TwitchDownloaderCLI.csproj
+++ b/TwitchDownloaderCLI/TwitchDownloaderCLI.csproj
@@ -7,7 +7,7 @@
Download and render Twitch VODs, clips, and chats
MIT
AnyCPU;x64
- net6.0
+ net8.0
default
diff --git a/TwitchDownloaderCore.Tests/TwitchDownloaderCore.Tests.csproj b/TwitchDownloaderCore.Tests/TwitchDownloaderCore.Tests.csproj
index d7c3d66e..35981faa 100644
--- a/TwitchDownloaderCore.Tests/TwitchDownloaderCore.Tests.csproj
+++ b/TwitchDownloaderCore.Tests/TwitchDownloaderCore.Tests.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net8.0
enable
enable
diff --git a/TwitchDownloaderCore/TwitchDownloaderCore.csproj b/TwitchDownloaderCore/TwitchDownloaderCore.csproj
index 267ca24f..13f59391 100644
--- a/TwitchDownloaderCore/TwitchDownloaderCore.csproj
+++ b/TwitchDownloaderCore/TwitchDownloaderCore.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net8.0
https://github.com/lay295/TwitchDownloader
true
MIT
diff --git a/TwitchDownloaderWPF/Properties/PublishProfiles/Windows.pubxml b/TwitchDownloaderWPF/Properties/PublishProfiles/Windows.pubxml
index 1f8a26b3..aeeb5abf 100644
--- a/TwitchDownloaderWPF/Properties/PublishProfiles/Windows.pubxml
+++ b/TwitchDownloaderWPF/Properties/PublishProfiles/Windows.pubxml
@@ -6,9 +6,9 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
Release
x64
- bin\Release\net6.0-windows\publish\win-x64\
+ bin\Release\net8.0-windows\publish\win-x64\
FileSystem
- net6.0-windows
+ net8.0-windows
win-x64
true
True
diff --git a/TwitchDownloaderWPF/TwitchDownloaderWPF.csproj b/TwitchDownloaderWPF/TwitchDownloaderWPF.csproj
index a7f3f880..6dbf7cd7 100644
--- a/TwitchDownloaderWPF/TwitchDownloaderWPF.csproj
+++ b/TwitchDownloaderWPF/TwitchDownloaderWPF.csproj
@@ -1,6 +1,6 @@
- net6.0-windows
+ net8.0-windows
WinExe
false
publish\
From 26423cc762b599f2b2a8f47f5da8b36f5ffaf4d2 Mon Sep 17 00:00:00 2001
From: ScrubN <72096833+ScrubN@users.noreply.github.com>
Date: Sun, 26 May 2024 16:25:59 -0400
Subject: [PATCH 2/9] Update README
---
README.md | 2 +-
README_es.md | 2 +-
README_it.md | 2 +-
README_ja.md | 2 +-
README_pt-br.md | 2 +-
README_tr.md | 2 +-
README_zh-cn.md | 2 +-
7 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index 0bad89b5..56e3b0fe 100644
--- a/README.md
+++ b/README.md
@@ -195,7 +195,7 @@ You can find more example commands in the [CLI README](TwitchDownloaderCLI/READM
## Requirements
-- [.NET 6.0.x SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
+- [.NET 8.0.x SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
- About 1GB of disk space
## Build Instructions
diff --git a/README_es.md b/README_es.md
index add2fef3..84311eda 100644
--- a/README_es.md
+++ b/README_es.md
@@ -161,7 +161,7 @@ chmod +x ffmpeg
## Requisitos
-- [.NET 6.0.x SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
+- [.NET 8.0.x SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
## Instrucciones de Compilación
diff --git a/README_it.md b/README_it.md
index 37e20fec..9dc90e2a 100644
--- a/README_it.md
+++ b/README_it.md
@@ -188,7 +188,7 @@ Puoi trovare altri esempi nel [CLI README](TwitchDownloaderCLI/README.md#example
## Requisiti
-- [.NET 6.0.x SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
+- [.NET 8.0.x SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
- Circa 1GB di spazio su disco
## Istruzioni
diff --git a/README_ja.md b/README_ja.md
index c72cbe0c..7cfe8bb8 100644
--- a/README_ja.md
+++ b/README_ja.md
@@ -187,7 +187,7 @@ chmod +x ffmpeg
## 必要条件
-- [.NET 6.0.x SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
+- [.NET 8.0.x SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
- 約1GBのディスク空き容量
## ビルド手順
diff --git a/README_pt-br.md b/README_pt-br.md
index 7f366f7c..af607843 100644
--- a/README_pt-br.md
+++ b/README_pt-br.md
@@ -188,7 +188,7 @@ Você pode encontrar mais comandos no [CLI README](TwitchDownloaderCLI/README.md
## Requerimentos
-- [.NET 6.0.x SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
+- [.NET 8.0.x SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
- Mais ou menos 1GB de espaço de disco.
## Instruções para construção
diff --git a/README_tr.md b/README_tr.md
index e3881922..4e431439 100644
--- a/README_tr.md
+++ b/README_tr.md
@@ -157,7 +157,7 @@ chmod +x ffmpeg
## Gereksinimler
-- [.NET 6.0.x SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
+- [.NET 8.0.x SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
## Derleme Talimatları
diff --git a/README_zh-cn.md b/README_zh-cn.md
index 4a90cf52..3793e4d4 100644
--- a/README_zh-cn.md
+++ b/README_zh-cn.md
@@ -188,7 +188,7 @@ chmod +x ffmpeg
## 要求
-- [.NET 6.0.x SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
+- [.NET 8.0.x SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
- 约 1GB 磁盘空间
## 构建说明
From 8aab875ad0c0cea6830816edbc5e12adf3e5653a Mon Sep 17 00:00:00 2001
From: ScrubN <72096833+ScrubN@users.noreply.github.com>
Date: Sun, 26 May 2024 17:08:24 -0400
Subject: [PATCH 3/9] Source generated regex everywhere!!
---
TwitchDownloaderCore/Chat/ChatJson.cs | 2 +-
TwitchDownloaderCore/ChatDownloader.cs | 2 +-
TwitchDownloaderCore/ChatRenderer.cs | 23 +++++----
.../Extensions/M3U8Extensions.cs | 19 ++++----
TwitchDownloaderCore/Tools/FilenameService.cs | 27 +++++++----
TwitchDownloaderCore/Tools/HighlightIcons.cs | 48 ++++++++++---------
TwitchDownloaderCore/Tools/TwitchRegex.cs | 29 ++++++-----
TwitchDownloaderCore/TwitchHelper.cs | 10 ++--
TwitchDownloaderCore/VideoDownloader.cs | 12 +++--
TwitchDownloaderWPF/PageChatDownload.xaml.cs | 2 +-
TwitchDownloaderWPF/PageVodDownload.xaml.cs | 2 +-
11 files changed, 100 insertions(+), 76 deletions(-)
diff --git a/TwitchDownloaderCore/Chat/ChatJson.cs b/TwitchDownloaderCore/Chat/ChatJson.cs
index 137f67b4..08fd0e20 100644
--- a/TwitchDownloaderCore/Chat/ChatJson.cs
+++ b/TwitchDownloaderCore/Chat/ChatJson.cs
@@ -231,7 +231,7 @@ private static async Task UpgradeChatJson(ChatRoot chatRoot)
{
foreach (var comment in chatRoot.comments)
{
- var bitMatch = TwitchRegex.BitsRegex.Match(comment.message.body);
+ var bitMatch = TwitchRegex.BitsRegex().Match(comment.message.body);
if (bitMatch.Success && int.TryParse(bitMatch.ValueSpan, out var result))
{
comment.message.bits_spent = result;
diff --git a/TwitchDownloaderCore/ChatDownloader.cs b/TwitchDownloaderCore/ChatDownloader.cs
index ef94a768..4de698bf 100644
--- a/TwitchDownloaderCore/ChatDownloader.cs
+++ b/TwitchDownloaderCore/ChatDownloader.cs
@@ -230,7 +230,7 @@ private static List ConvertComments(CommentVideo video, ChatFormat form
message.body = bodyStringBuilder.ToString();
- var bitMatch = TwitchRegex.BitsRegex.Match(message.body);
+ var bitMatch = TwitchRegex.BitsRegex().Match(message.body);
if (bitMatch.Success && int.TryParse(bitMatch.ValueSpan, out var result))
{
message.bits_spent = result;
diff --git a/TwitchDownloaderCore/ChatRenderer.cs b/TwitchDownloaderCore/ChatRenderer.cs
index 62bb68f6..c40d69d5 100644
--- a/TwitchDownloaderCore/ChatRenderer.cs
+++ b/TwitchDownloaderCore/ChatRenderer.cs
@@ -23,7 +23,7 @@
namespace TwitchDownloaderCore
{
- public sealed class ChatRenderer : IDisposable
+ public partial class ChatRenderer : IDisposable
{
public bool Disposed { get; private set; } = false;
public ChatRoot chatRoot { get; private set; } = new ChatRoot();
@@ -31,10 +31,14 @@ public sealed class ChatRenderer : IDisposable
private static readonly SKColor Purple = SKColor.Parse("#7B2CF2");
private static readonly SKColor[] DefaultUsernameColors = { SKColor.Parse("#FF0000"), SKColor.Parse("#0000FF"), SKColor.Parse("#00FF00"), SKColor.Parse("#B22222"), SKColor.Parse("#FF7F50"), SKColor.Parse("#9ACD32"), SKColor.Parse("#FF4500"), SKColor.Parse("#2E8B57"), SKColor.Parse("#DAA520"), SKColor.Parse("#D2691E"), SKColor.Parse("#5F9EA0"), SKColor.Parse("#1E90FF"), SKColor.Parse("#FF69B4"), SKColor.Parse("#8A2BE2"), SKColor.Parse("#00FF7F") };
- private static readonly Regex RtlRegex = new("[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]", RegexOptions.Compiled);
- private static readonly Regex BlockArtRegex = new("[\u2500-\u257F\u2580-\u259F\u2800-\u28FF]", RegexOptions.Compiled);
- private static readonly Regex EmojiRegex = new(@"(?:[#*0-9]\uFE0F?\u20E3|©\uFE0F?|[®\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26F9(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC3\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEDD-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC08(?:\u200D\u2B1B)?|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE])))?))?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDD75(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF6](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7C\uDE80-\uDE86\uDE90-\uDEAC\uDEB0-\uDEBA\uDEC0-\uDEC2\uDED0-\uDED9\uDEE0-\uDEE7]|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF])?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?))",
- RegexOptions.Compiled);
+ [GeneratedRegex("[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]")]
+ private static partial Regex RtlRegex();
+
+ [GeneratedRegex("[\u2500-\u257F\u2580-\u259F\u2800-\u28FF]")]
+ private static partial Regex BlockArtRegex();
+
+ [GeneratedRegex(@"(?:[#*0-9]\uFE0F?\u20E3|©\uFE0F?|[®\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26F9(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC3\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEDD-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC08(?:\u200D\u2B1B)?|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE])))?))?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDD75(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF6](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7C\uDE80-\uDE86\uDE90-\uDEAC\uDEB0-\uDEBA\uDEC0-\uDEC2\uDED0-\uDED9\uDEE0-\uDEE7]|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF])?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?))")]
+ private static partial Regex EmojiRegex();
// TODO: Use FrozenDictionary when .NET 8
private static readonly IReadOnlyDictionary AllEmojiSequences = Emoji.All.ToDictionary(e => e.SortOrder, e => e.Sequence.AsString);
@@ -872,7 +876,7 @@ private void DrawFragmentPart(List<(SKImageInfo info, SKBitmap bitmap)> sectionI
{
DrawThirdPartyEmote(sectionImages, emotePositionList, ref drawPos, defaultPos, emote, highlightWords);
}
- else if (!skipEmoji && EmojiRegex.IsMatch(fragmentPart))
+ else if (!skipEmoji && EmojiRegex().IsMatch(fragmentPart))
{
DrawEmojiMessage(sectionImages, emotePositionList, ref drawPos, defaultPos, bitsCount, fragmentPart, highlightWords);
}
@@ -1048,10 +1052,9 @@ private void DrawEmojiMessage(List<(SKImageInfo info, SKBitmap bitmap)> sectionI
private void DrawNonFontMessage(List<(SKImageInfo info, SKBitmap bitmap)> sectionImages, ref Point drawPos, Point defaultPos, string fragmentString, bool highlightWords)
{
- ReadOnlySpan fragmentSpan = fragmentString.AsSpan().Trim('\uFE0F');
+ var fragmentSpan = fragmentString.AsSpan().Trim('\uFE0F');
- // TODO: use fragmentSpan instead of fragmentString once upgraded to .NET 7
- if (BlockArtRegex.IsMatch(fragmentString))
+ if (BlockArtRegex().IsMatch(fragmentSpan))
{
// Very rough estimation of width of block art
int textWidth = (int)(fragmentSpan.Length * renderOptions.BlockArtCharWidth);
@@ -1298,7 +1301,7 @@ private void DrawText(string drawText, SKPaint textFont, bool padding, List<(SKI
sectionImageCanvas.DrawPath(outlinePath, outlinePaint);
}
- if (RtlRegex.IsMatch(drawText))
+ if (RtlRegex().IsMatch(drawText))
{
sectionImageCanvas.DrawShapedText(drawText, drawPos.X, drawPos.Y, textFont);
}
diff --git a/TwitchDownloaderCore/Extensions/M3U8Extensions.cs b/TwitchDownloaderCore/Extensions/M3U8Extensions.cs
index 3ef590fb..7e840fae 100644
--- a/TwitchDownloaderCore/Extensions/M3U8Extensions.cs
+++ b/TwitchDownloaderCore/Extensions/M3U8Extensions.cs
@@ -5,7 +5,7 @@
namespace TwitchDownloaderCore.Extensions
{
- public static class M3U8Extensions
+ public static partial class M3U8Extensions
{
public static void SortStreamsByQuality(this M3U8 m3u8)
{
@@ -21,8 +21,8 @@ public static void SortStreamsByQuality(this M3U8 m3u8)
}
}
- private static readonly Regex UserQualityStringRegex = new(@"(?:^|\s)(?:(?\d{3,4})x)?(?\d{3,4})p?(?\d{1,3})?(?:$|\s)",
- RegexOptions.IgnoreCase | RegexOptions.Compiled);
+ [GeneratedRegex(@"(?:^|\s)(?:(?\d{3,4})x)?(?\d{3,4})p?(?\d{1,3})?(?:$|\s)", RegexOptions.IgnoreCase)]
+ private static partial Regex UserQualityStringRegex();
public static M3U8.Stream GetStreamOfQuality(this M3U8 m3u8, string qualityString)
{
@@ -48,7 +48,7 @@ public static M3U8.Stream GetStreamOfQuality(this M3U8 m3u8, string qualityStrin
}
}
- var qualityStringMatch = UserQualityStringRegex.Match(qualityString);
+ var qualityStringMatch = UserQualityStringRegex().Match(qualityString);
if (!qualityStringMatch.Success)
{
return m3u8.BestQualityStream();
@@ -105,27 +105,28 @@ private static bool TryGetKeywordStream(M3U8 m3u8, string qualityString, out M3U
return false;
}
+ [GeneratedRegex(@"\d{3,4}p\d{2,3}")]
+ private static partial Regex ResolutionFramerateRegex();
+
///
/// A representing the 's
/// and in the format of "{resolution}p{framerate}" or
///
public static string GetResolutionFramerateString(this M3U8.Stream stream)
{
- const string RESOLUTION_FRAMERATE_PATTERN = /*lang=regex*/@"\d{3,4}p\d{2,3}";
-
var mediaInfo = stream.MediaInfo;
- if (stream.IsAudioOnly() || Regex.IsMatch(mediaInfo.Name, RESOLUTION_FRAMERATE_PATTERN))
+ if (stream.IsAudioOnly() || ResolutionFramerateRegex().IsMatch(mediaInfo.Name))
{
return mediaInfo.Name;
}
var streamInfo = stream.StreamInfo;
- if (Regex.IsMatch(streamInfo.Video, RESOLUTION_FRAMERATE_PATTERN))
+ if (ResolutionFramerateRegex().IsMatch(streamInfo.Video))
{
return streamInfo.Video;
}
- if (Regex.IsMatch(mediaInfo.GroupId, RESOLUTION_FRAMERATE_PATTERN))
+ if (ResolutionFramerateRegex().IsMatch(mediaInfo.GroupId))
{
return mediaInfo.GroupId;
}
diff --git a/TwitchDownloaderCore/Tools/FilenameService.cs b/TwitchDownloaderCore/Tools/FilenameService.cs
index 2f8a1c0e..1de94b19 100644
--- a/TwitchDownloaderCore/Tools/FilenameService.cs
+++ b/TwitchDownloaderCore/Tools/FilenameService.cs
@@ -6,8 +6,20 @@
namespace TwitchDownloaderCore.Tools
{
- public static class FilenameService
+ public static partial class FilenameService
{
+ [GeneratedRegex("{date_custom=\"(.*?)\"}")]
+ private static partial Regex DateCustomRegex();
+
+ [GeneratedRegex("{trim_start_custom=\"(.*?)\"}")]
+ private static partial Regex TrimStartCustomRegex();
+
+ [GeneratedRegex("{trim_end_custom=\"(.*?)\"}")]
+ private static partial Regex TrimEndCustomRegex();
+
+ [GeneratedRegex("{length_custom=\"(.*?)\"}")]
+ private static partial Regex LengthCustomRegex();
+
public static string GetFilename(string template, string title, string id, DateTime date, string channel, TimeSpan trimStart, TimeSpan trimEnd, string viewCount, string game)
{
var videoLength = trimEnd - trimStart;
@@ -26,26 +38,22 @@ public static string GetFilename(string template, string title, string id, DateT
if (template.Contains("{date_custom="))
{
- var dateRegex = new Regex("{date_custom=\"(.*?)\"}");
- ReplaceCustomWithFormattable(stringBuilder, dateRegex, date);
+ ReplaceCustomWithFormattable(stringBuilder, DateCustomRegex(), date);
}
if (template.Contains("{trim_start_custom="))
{
- var trimStartRegex = new Regex("{trim_start_custom=\"(.*?)\"}");
- ReplaceCustomWithFormattable(stringBuilder, trimStartRegex, trimStart);
+ ReplaceCustomWithFormattable(stringBuilder, TrimStartCustomRegex(), trimStart);
}
if (template.Contains("{trim_end_custom="))
{
- var trimEndRegex = new Regex("{trim_end_custom=\"(.*?)\"}");
- ReplaceCustomWithFormattable(stringBuilder, trimEndRegex, trimEnd);
+ ReplaceCustomWithFormattable(stringBuilder, TrimEndCustomRegex(), trimEnd);
}
if (template.Contains("{length_custom="))
{
- var lengthRegex = new Regex("{length_custom=\"(.*?)\"}");
- ReplaceCustomWithFormattable(stringBuilder, lengthRegex, videoLength);
+ ReplaceCustomWithFormattable(stringBuilder, LengthCustomRegex(), videoLength);
}
var fileName = stringBuilder.ToString();
@@ -58,7 +66,6 @@ private static void ReplaceCustomWithFormattable(StringBuilder sb, Regex regex,
do
{
// There's probably a better way to do this that doesn't require calling ToString()
- // However we need .NET7+ for span support in the regex matcher.
var match = regex.Match(sb.ToString());
if (!match.Success)
break;
diff --git a/TwitchDownloaderCore/Tools/HighlightIcons.cs b/TwitchDownloaderCore/Tools/HighlightIcons.cs
index aee70c39..c5eb996b 100644
--- a/TwitchDownloaderCore/Tools/HighlightIcons.cs
+++ b/TwitchDownloaderCore/Tools/HighlightIcons.cs
@@ -27,7 +27,7 @@ public enum HighlightType
Unknown
}
- public sealed class HighlightIcons : IDisposable
+ public sealed partial class HighlightIcons : IDisposable
{
public bool Disposed { get; private set; }
@@ -43,9 +43,14 @@ public sealed class HighlightIcons : IDisposable
private const int ICON_SIZE = 72; // Icon SVG strings are scaled for 72x72
- private static readonly Regex SubMessageRegex = new(@"^((?:\w+ )?subscribed (?:with Prime|at Tier \d)\. They've subscribed for \d{1,3} months(?:, currently on a \d{1,3} month streak)?! )(.+)$", RegexOptions.Compiled);
- private static readonly Regex GiftAnonymousRegex = new(@"^An anonymous user (?:gifted a|is gifting \d{1,4}) Tier \d", RegexOptions.Compiled);
- private static readonly Regex WatchStreakRegex = new(@"^((?:\w+ )?watched \d+ consecutive streams this month and sparked a watch streak! )(.+)$", RegexOptions.Compiled);
+ [GeneratedRegex(@"^((?:\w+ )?subscribed (?:with Prime|at Tier \d)\. They've subscribed for \d{1,3} months(?:, currently on a \d{1,3} month streak)?! )(.+)$")]
+ private static partial Regex SubMessageRegex();
+
+ [GeneratedRegex(@"^An anonymous user (?:gifted a|is gifting \d{1,4}) Tier \d")]
+ private static partial Regex GiftAnonymousRegex();
+
+ [GeneratedRegex(@"^((?:\w+ )?watched \d+ consecutive streams this month and sparked a watch streak! )(.+)$")]
+ private static partial Regex WatchStreakRegex();
private SKImage _subscribedTierIcon;
private SKImage _subscribedPrimeIcon;
@@ -118,20 +123,20 @@ public static HighlightType GetHighlightType(Comment comment)
if (bodyWithoutName.StartsWith(" converted from a"))
{
- // TODO: use bodyWithoutName when .NET 7
- var convertedToMatch = Regex.Match(comment.message.body, $@"(?<=^{comment.commenter.display_name} converted from a (?:Prime|Tier \d) sub to a )(?:Prime|Tier \d)");
- if (!convertedToMatch.Success)
- return HighlightType.None;
-
- // TODO: use ValueSpan when .NET 7
- return convertedToMatch.Value switch
+ var slice = bodyWithoutName[17..];
+ foreach (var match in Regex.EnumerateMatches(slice, @"(?<= (?:Prime|Tier \d) sub to a )(?:Prime|Tier \d)"))
{
- "Prime" => HighlightType.SubscribedPrime,
- "Tier 1" => HighlightType.SubscribedTier,
- "Tier 2" => HighlightType.SubscribedTier,
- "Tier 3" => HighlightType.SubscribedTier,
- _ => HighlightType.None
- };
+ return slice.Slice(match.Index, match.Length) switch
+ {
+ "Prime" => HighlightType.SubscribedPrime,
+ "Tier 1" => HighlightType.SubscribedTier,
+ "Tier 2" => HighlightType.SubscribedTier,
+ "Tier 3" => HighlightType.SubscribedTier,
+ _ => HighlightType.None
+ };
+ }
+
+ return HighlightType.None;
}
}
@@ -140,13 +145,12 @@ public static HighlightType GetHighlightType(Comment comment)
if (char.IsDigit(bodySpan[0]) && bodySpan.EndsWith(" have joined! "))
{
- // TODO: use bodySpan when .NET 7
- if (Regex.IsMatch(comment.message.body, $@"^\d+ raiders from {comment.commenter.display_name} have joined! "))
+ if (Regex.IsMatch(bodySpan, $@"^\d+ raiders from {comment.commenter.display_name} have joined! "))
return HighlightType.Raid;
}
const string ANONYMOUS_GIFT_ACCOUNT_ID = "274598607"; // Display name is 'AnAnonymousGifter'
- if (comment.commenter._id is ANONYMOUS_GIFT_ACCOUNT_ID && GiftAnonymousRegex.IsMatch(comment.message.body))
+ if (comment.commenter._id is ANONYMOUS_GIFT_ACCOUNT_ID && GiftAnonymousRegex().IsMatch(comment.message.body))
return HighlightType.GiftedAnonymous;
return HighlightType.None;
@@ -243,7 +247,7 @@ private SKPaint GetSvgIconPaint(SKColor iconColor)
///
public static (Comment subMessage, Comment customMessage) SplitSubComment(Comment comment)
{
- var subMessageMatch = SubMessageRegex.Match(comment.message.body);
+ var subMessageMatch = SubMessageRegex().Match(comment.message.body);
if (!subMessageMatch.Success)
{
// Return the original comment + null if there is no custom sub message
@@ -291,7 +295,7 @@ public static (Comment subMessage, Comment customMessage) SplitSubComment(Commen
///
public static (Comment subMessage, Comment customMessage) SplitWatchStreakComment(Comment comment)
{
- var watchStreakMatch = WatchStreakRegex.Match(comment.message.body);
+ var watchStreakMatch = WatchStreakRegex().Match(comment.message.body);
if (!watchStreakMatch.Success)
{
// Return the original comment + null if there is no custom watch streak message
diff --git a/TwitchDownloaderCore/Tools/TwitchRegex.cs b/TwitchDownloaderCore/Tools/TwitchRegex.cs
index fa5f718c..98a198aa 100644
--- a/TwitchDownloaderCore/Tools/TwitchRegex.cs
+++ b/TwitchDownloaderCore/Tools/TwitchRegex.cs
@@ -3,28 +3,33 @@
namespace TwitchDownloaderCore.Tools
{
- public static class TwitchRegex
+ public static partial class TwitchRegex
{
- // TODO: Use source generators when .NET7
- private static readonly Regex VideoId = new(@"(?<=^|twitch\.tv\/videos\/)\d+(?=$|\?|\s)", RegexOptions.Compiled);
- private static readonly Regex HighlightId = new(@"(?<=^|twitch\.tv\/\w+\/v(?:ideo)?\/)\d+(?=$|\?|\s)", RegexOptions.Compiled);
- private static readonly Regex ClipId = new(@"(?<=^|(?:clips\.)?twitch\.tv\/(?:\w+\/clip\/)?)[\w-]+?(?=$|\?|\s)", RegexOptions.Compiled);
+ [GeneratedRegex("@\"(?<=^|twitch\\.tv\\/videos\\/)\\d+(?=$|\\?|\\s)\"")]
+ private static partial Regex VideoId();
- public static readonly Regex UrlTimeCode = new(@"(?<=(?:\?|&)t=)\d+h\d+m\d+s(?=$|\?|\s)", RegexOptions.Compiled);
- public static readonly Regex BitsRegex = new(
- @"(?<=(?:\s|^)(?:4Head|Anon|Bi(?:bleThumb|tBoss)|bday|C(?:h(?:eer|arity)|orgo)|cheerwal|D(?:ansGame|oodleCheer)|EleGiggle|F(?:rankerZ|ailFish)|Goal|H(?:eyGuys|olidayCheer)|K(?:appa|reygasm)|M(?:rDestructoid|uxy)|NotLikeThis|P(?:arty|ride|JSalt)|RIPCheer|S(?:coops|h(?:owLove|amrock)|eemsGood|wiftRage|treamlabs)|TriHard|uni|VoHiYo))[1-9]\d{0,6}(?=\s|$)",
- RegexOptions.Compiled);
+ [GeneratedRegex(@"(?<=^|twitch\.tv\/\w+\/v(?:ideo)?\/)\d+(?=$|\?|\s)")]
+ private static partial Regex HighlightId();
+
+ [GeneratedRegex(@"(?<=^|(?:clips\.)?twitch\.tv\/(?:\w+\/clip\/)?)[\w-]+?(?=$|\?|\s)")]
+ private static partial Regex ClipId();
+
+ [GeneratedRegex(@"(?<=(?:\?|&)t=)\d+h\d+m\d+s(?=$|\?|\s)")]
+ public static partial Regex UrlTimeCode();
+
+ [GeneratedRegex(@"(?<=(?:\s|^)(?:4Head|Anon|Bi(?:bleThumb|tBoss)|bday|C(?:h(?:eer|arity)|orgo)|cheerwal|D(?:ansGame|oodleCheer)|EleGiggle|F(?:rankerZ|ailFish)|Goal|H(?:eyGuys|olidayCheer)|K(?:appa|reygasm)|M(?:rDestructoid|uxy)|NotLikeThis|P(?:arty|ride|JSalt)|RIPCheer|S(?:coops|h(?:owLove|amrock)|eemsGood|wiftRage|treamlabs)|TriHard|uni|VoHiYo))[1-9]\d{0,6}(?=\s|$)")]
+ public static partial Regex BitsRegex();
/// A of the video's id or .
public static Match MatchVideoId(string text)
{
- var videoIdMatch = VideoId.Match(text);
+ var videoIdMatch = VideoId().Match(text);
if (videoIdMatch.Success)
{
return videoIdMatch;
}
- var highlightIdMatch = HighlightId.Match(text);
+ var highlightIdMatch = HighlightId().Match(text);
if (highlightIdMatch.Success)
{
return highlightIdMatch;
@@ -36,7 +41,7 @@ public static Match MatchVideoId(string text)
/// A of the clip's id or .
public static Match MatchClipId(string text)
{
- var clipIdMatch = ClipId.Match(text);
+ var clipIdMatch = ClipId().Match(text);
if (clipIdMatch.Success && !clipIdMatch.Value.All(char.IsDigit))
{
return clipIdMatch;
diff --git a/TwitchDownloaderCore/TwitchHelper.cs b/TwitchDownloaderCore/TwitchHelper.cs
index 06b1d5e4..ae992400 100644
--- a/TwitchDownloaderCore/TwitchHelper.cs
+++ b/TwitchDownloaderCore/TwitchHelper.cs
@@ -22,7 +22,7 @@
namespace TwitchDownloaderCore
{
- public static class TwitchHelper
+ public static partial class TwitchHelper
{
private static readonly HttpClient httpClient = new HttpClient();
private static readonly string[] BttvZeroWidth = { "SoSnowy", "IceCold", "SantaHat", "TopHat", "ReinDeer", "CandyCane", "cvMask", "cvHazmat" };
@@ -671,6 +671,9 @@ public static async Task> GetChatBadges(List comments,
return returnList;
}
+ [GeneratedRegex(@"\.(?:png|PNG)$", RegexOptions.RightToLeft)]
+ private static partial Regex EmojiExtensionRegex();
+
public static async Task> GetEmojis(string cacheFolder, EmojiVendor emojiVendor, ITaskLogger logger, CancellationToken cancellationToken = default)
{
var returnCache = new Dictionary();
@@ -679,13 +682,12 @@ public static async Task> GetEmojis(string cacheFol
return returnCache;
var emojiFolder = Path.Combine(cacheFolder, "emojis", emojiVendor.EmojiFolder());
- var emojiExtensions = new Regex(@"\.(?:png|PNG)$", RegexOptions.RightToLeft); // Extensions are case sensitive on Linux and Mac
if (!Directory.Exists(emojiFolder))
CreateDirectory(emojiFolder);
var emojiFiles = Directory.GetFiles(emojiFolder)
- .Where(i => emojiExtensions.IsMatch(i)).ToArray();
+ .Where(i => EmojiExtensionRegex().IsMatch(i)).ToArray();
if (emojiFiles.Length < emojiVendor.EmojiCount())
{
@@ -719,7 +721,7 @@ public static async Task> GetEmojis(string cacheFol
}
emojiFiles = Directory.GetFiles(emojiFolder)
- .Where(i => emojiExtensions.IsMatch(i)).ToArray();
+ .Where(i => EmojiExtensionRegex().IsMatch(i)).ToArray();
}
finally
{
diff --git a/TwitchDownloaderCore/VideoDownloader.cs b/TwitchDownloaderCore/VideoDownloader.cs
index 5a109a3a..65d9cf08 100644
--- a/TwitchDownloaderCore/VideoDownloader.cs
+++ b/TwitchDownloaderCore/VideoDownloader.cs
@@ -19,7 +19,7 @@
namespace TwitchDownloaderCore
{
- public sealed class VideoDownloader
+ public sealed partial class VideoDownloader
{
private readonly VideoDownloadOptions downloadOptions;
private readonly HttpClient _httpClient = new() { Timeout = TimeSpan.FromSeconds(30) };
@@ -348,7 +348,6 @@ private int RunFfmpegVideoCopy(string tempFolder, FileInfo outputFile, string me
}
};
- var encodingTimeRegex = new Regex(@"(?<=time=)(\d\d):(\d\d):(\d\d)\.(\d\d)", RegexOptions.Compiled);
var logQueue = new ConcurrentQueue();
process.ErrorDataReceived += (sender, e) =>
@@ -358,7 +357,7 @@ private int RunFfmpegVideoCopy(string tempFolder, FileInfo outputFile, string me
logQueue.Enqueue(e.Data); // We cannot use -report ffmpeg arg because it redirects stderr
- HandleFfmpegOutput(e.Data, encodingTimeRegex, seekDuration);
+ HandleFfmpegOutput(e.Data, seekDuration);
};
process.Start();
@@ -377,9 +376,12 @@ private int RunFfmpegVideoCopy(string tempFolder, FileInfo outputFile, string me
return process.ExitCode;
}
- private void HandleFfmpegOutput(string output, Regex encodingTimeRegex, TimeSpan videoLength)
+ [GeneratedRegex(@"(?<=time=)(\d\d):(\d\d):(\d\d)\.(\d\d)")]
+ private static partial Regex EncodingTimeRegex();
+
+ private void HandleFfmpegOutput(string output, TimeSpan videoLength)
{
- var encodingTimeMatch = encodingTimeRegex.Match(output);
+ var encodingTimeMatch = EncodingTimeRegex().Match(output);
if (!encodingTimeMatch.Success)
return;
diff --git a/TwitchDownloaderWPF/PageChatDownload.xaml.cs b/TwitchDownloaderWPF/PageChatDownload.xaml.cs
index d4cbdba2..780f175f 100644
--- a/TwitchDownloaderWPF/PageChatDownload.xaml.cs
+++ b/TwitchDownloaderWPF/PageChatDownload.xaml.cs
@@ -134,7 +134,7 @@ private async Task GetVideoInfo()
streamerId = int.Parse(videoInfo.data.video.owner.id);
viewCount = videoInfo.data.video.viewCount;
game = videoInfo.data.video.game?.displayName ?? Translations.Strings.UnknownGame;
- var urlTimeCodeMatch = TwitchRegex.UrlTimeCode.Match(textUrl.Text);
+ var urlTimeCodeMatch = TwitchRegex.UrlTimeCode().Match(textUrl.Text);
if (urlTimeCodeMatch.Success)
{
var time = UrlTimeCode.Parse(urlTimeCodeMatch.ValueSpan);
diff --git a/TwitchDownloaderWPF/PageVodDownload.xaml.cs b/TwitchDownloaderWPF/PageVodDownload.xaml.cs
index ae663436..2b28498c 100644
--- a/TwitchDownloaderWPF/PageVodDownload.xaml.cs
+++ b/TwitchDownloaderWPF/PageVodDownload.xaml.cs
@@ -140,7 +140,7 @@ private async Task GetVideoInfo()
var videoCreatedAt = taskVideoInfo.Result.data.video.createdAt;
textCreatedAt.Text = Settings.Default.UTCVideoTime ? videoCreatedAt.ToString(CultureInfo.CurrentCulture) : videoCreatedAt.ToLocalTime().ToString(CultureInfo.CurrentCulture);
currentVideoTime = Settings.Default.UTCVideoTime ? videoCreatedAt : videoCreatedAt.ToLocalTime();
- var urlTimeCodeMatch = TwitchRegex.UrlTimeCode.Match(textUrl.Text);
+ var urlTimeCodeMatch = TwitchRegex.UrlTimeCode().Match(textUrl.Text);
if (urlTimeCodeMatch.Success)
{
var time = UrlTimeCode.Parse(urlTimeCodeMatch.ValueSpan);
From 5c923aa25781e10a68599b79f72f83457b256195 Mon Sep 17 00:00:00 2001
From: ScrubN <72096833+ScrubN@users.noreply.github.com>
Date: Sun, 26 May 2024 17:39:00 -0400
Subject: [PATCH 4/9] Annotate with StringSyntaxAttribute
---
TwitchDownloaderCLI/Tools/CliTaskProgress.cs | 9 +++++----
TwitchDownloaderCore/Interfaces/ITaskProgress.cs | 6 +++---
TwitchDownloaderCore/Tools/StubTaskProgress.cs | 5 +++--
TwitchDownloaderCore/Tools/TimeSpanHFormat.cs | 5 +++--
TwitchDownloaderWPF/Utils/WpfTaskProgress.cs | 9 +++++----
5 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/TwitchDownloaderCLI/Tools/CliTaskProgress.cs b/TwitchDownloaderCLI/Tools/CliTaskProgress.cs
index 7b873c82..61f5e523 100644
--- a/TwitchDownloaderCLI/Tools/CliTaskProgress.cs
+++ b/TwitchDownloaderCLI/Tools/CliTaskProgress.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using TwitchDownloaderCLI.Models;
using TwitchDownloaderCore.Interfaces;
@@ -46,13 +47,13 @@ public void SetStatus(string status)
}
}
- public void SetTemplateStatus(string status, int initialPercent)
+ public void SetTemplateStatus([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string statusTemplate, int initialPercent)
{
if ((_logLevel & LogLevel.Status) == 0) return;
lock (this)
{
- _status = status;
+ _status = statusTemplate;
_statusIsTemplate = true;
if (!_lastWriteHadNewLine)
@@ -65,13 +66,13 @@ public void SetTemplateStatus(string status, int initialPercent)
}
}
- public void SetTemplateStatus(string status, int initialPercent, TimeSpan initialTime1, TimeSpan initialTime2)
+ public void SetTemplateStatus([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string statusTemplate, int initialPercent, TimeSpan initialTime1, TimeSpan initialTime2)
{
if ((_logLevel & LogLevel.Status) == 0) return;
lock (this)
{
- _status = status;
+ _status = statusTemplate;
_statusIsTemplate = true;
if (!_lastWriteHadNewLine)
diff --git a/TwitchDownloaderCore/Interfaces/ITaskProgress.cs b/TwitchDownloaderCore/Interfaces/ITaskProgress.cs
index a14460e4..09638440 100644
--- a/TwitchDownloaderCore/Interfaces/ITaskProgress.cs
+++ b/TwitchDownloaderCore/Interfaces/ITaskProgress.cs
@@ -1,13 +1,13 @@
using System;
+using System.Diagnostics.CodeAnalysis;
namespace TwitchDownloaderCore.Interfaces
{
- // TODO: Add StringSyntaxAttributes when .NET 7+
public interface ITaskProgress : ITaskLogger
{
void SetStatus(string status);
- void SetTemplateStatus(string status, int initialPercent);
- void SetTemplateStatus(string status, int initialPercent, TimeSpan initialTime1, TimeSpan initialTime2);
+ void SetTemplateStatus([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string statusTemplate, int initialPercent);
+ void SetTemplateStatus([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string statusTemplate, int initialPercent, TimeSpan initialTime1, TimeSpan initialTime2);
void ReportProgress(int percent);
void ReportProgress(int percent, TimeSpan time1, TimeSpan time2);
}
diff --git a/TwitchDownloaderCore/Tools/StubTaskProgress.cs b/TwitchDownloaderCore/Tools/StubTaskProgress.cs
index a044430e..fc25a7e0 100644
--- a/TwitchDownloaderCore/Tools/StubTaskProgress.cs
+++ b/TwitchDownloaderCore/Tools/StubTaskProgress.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using TwitchDownloaderCore.Interfaces;
@@ -30,9 +31,9 @@ public void LogFfmpeg(string logMessage) { }
public void SetStatus(string status) { }
- public void SetTemplateStatus(string status, int initialPercent) { }
+ public void SetTemplateStatus([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string statusTemplate, int initialPercent) { }
- public void SetTemplateStatus(string status, int initialPercent, TimeSpan initialTime1, TimeSpan initialTime2) { }
+ public void SetTemplateStatus([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string statusTemplate, int initialPercent, TimeSpan initialTime1, TimeSpan initialTime2) { }
public void ReportProgress(int percent) { }
diff --git a/TwitchDownloaderCore/Tools/TimeSpanHFormat.cs b/TwitchDownloaderCore/Tools/TimeSpanHFormat.cs
index 3e711b81..0babd791 100644
--- a/TwitchDownloaderCore/Tools/TimeSpanHFormat.cs
+++ b/TwitchDownloaderCore/Tools/TimeSpanHFormat.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Text;
using TwitchDownloaderCore.Extensions;
@@ -20,7 +21,7 @@ public object GetFormat(Type formatType)
return null;
}
- public string Format(string format, object arg, IFormatProvider formatProvider = null)
+ public string Format([StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] string format, object arg, IFormatProvider formatProvider = null)
{
if (arg is TimeSpan timeSpan)
{
@@ -32,7 +33,7 @@ public string Format(string format, object arg, IFormatProvider formatProvider =
/// Provides an identical output to but without boxing the .
/// This method is not part of the interface.
- public string Format(string format, TimeSpan timeSpan, IFormatProvider formatProvider = null)
+ public string Format([StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] string format, TimeSpan timeSpan, IFormatProvider formatProvider = null)
{
if (string.IsNullOrEmpty(format))
{
diff --git a/TwitchDownloaderWPF/Utils/WpfTaskProgress.cs b/TwitchDownloaderWPF/Utils/WpfTaskProgress.cs
index 02a8fae3..355f3ed5 100644
--- a/TwitchDownloaderWPF/Utils/WpfTaskProgress.cs
+++ b/TwitchDownloaderWPF/Utils/WpfTaskProgress.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using TwitchDownloaderCore.Interfaces;
using TwitchDownloaderWPF.Models;
@@ -57,11 +58,11 @@ public void SetStatus(string status)
}
}
- public void SetTemplateStatus(string status, int initialPercent)
+ public void SetTemplateStatus([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string statusTemplate, int initialPercent)
{
lock (this)
{
- _status = status;
+ _status = statusTemplate;
_statusIsTemplate = true;
_lastPercent = -1; // Ensure that the progress report runs
@@ -69,11 +70,11 @@ public void SetTemplateStatus(string status, int initialPercent)
}
}
- public void SetTemplateStatus(string status, int initialPercent, TimeSpan initialTime1, TimeSpan initialTime2)
+ public void SetTemplateStatus([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string statusTemplate, int initialPercent, TimeSpan initialTime1, TimeSpan initialTime2)
{
lock (this)
{
- _status = status;
+ _status = statusTemplate;
_statusIsTemplate = true;
_lastPercent = -1; // Ensure that the progress report runs
From 060b5bd875b27e9415eed266e6646ff16116eef8 Mon Sep 17 00:00:00 2001
From: ScrubN <72096833+ScrubN@users.noreply.github.com>
Date: Sun, 26 May 2024 17:39:42 -0400
Subject: [PATCH 5/9] Use frozen dictionary
---
TwitchDownloaderCore/ChatRenderer.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/TwitchDownloaderCore/ChatRenderer.cs b/TwitchDownloaderCore/ChatRenderer.cs
index c40d69d5..57e2ae63 100644
--- a/TwitchDownloaderCore/ChatRenderer.cs
+++ b/TwitchDownloaderCore/ChatRenderer.cs
@@ -3,6 +3,7 @@
using SkiaSharp.HarfBuzz;
using System;
using System.Collections.Concurrent;
+using System.Collections.Frozen;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
@@ -40,8 +41,7 @@ public partial class ChatRenderer : IDisposable
[GeneratedRegex(@"(?:[#*0-9]\uFE0F?\u20E3|©\uFE0F?|[®\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26F9(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC3\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEDD-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC08(?:\u200D\u2B1B)?|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE])))?))?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDD75(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF6](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7C\uDE80-\uDE86\uDE90-\uDEAC\uDEB0-\uDEBA\uDEC0-\uDEC2\uDED0-\uDED9\uDEE0-\uDEE7]|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF])?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?))")]
private static partial Regex EmojiRegex();
- // TODO: Use FrozenDictionary when .NET 8
- private static readonly IReadOnlyDictionary AllEmojiSequences = Emoji.All.ToDictionary(e => e.SortOrder, e => e.Sequence.AsString);
+ private static readonly IReadOnlyDictionary AllEmojiSequences = Emoji.All.ToFrozenDictionary(e => e.SortOrder, e => e.Sequence.AsString);
private readonly ITaskProgress _progress;
private readonly ChatRenderOptions renderOptions;
From 5df8a80c3ff8988a0ee68feba1d04756912b1d61 Mon Sep 17 00:00:00 2001
From: ScrubN <72096833+ScrubN@users.noreply.github.com>
Date: Sun, 26 May 2024 17:45:19 -0400
Subject: [PATCH 6/9] Use list patterns
---
TwitchDownloaderCore/Chat/ChatJson.cs | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/TwitchDownloaderCore/Chat/ChatJson.cs b/TwitchDownloaderCore/Chat/ChatJson.cs
index 08fd0e20..98a7b186 100644
--- a/TwitchDownloaderCore/Chat/ChatJson.cs
+++ b/TwitchDownloaderCore/Chat/ChatJson.cs
@@ -131,31 +131,30 @@ private static async Task GetJsonDocumentAsync(Stream stream, stri
stream.Seek(-RENT_LENGTH, SeekOrigin.Current);
- // TODO: use list patterns when .NET 7+
// https://en.wikipedia.org/wiki/Byte_order_mark#Byte_order_marks_by_encoding
- switch (rentedBuffer[0], rentedBuffer[1], rentedBuffer[2], rentedBuffer[3])
+ switch (rentedBuffer)
{
- case (0x1F, 0x8B, _, _): // https://docs.fileformat.com/compression/gz/#gz-file-header
+ case [0x1F, 0x8B, ..]: // https://docs.fileformat.com/compression/gz/#gz-file-header
{
await using var gs = new GZipStream(stream, CompressionMode.Decompress);
return await GetJsonDocumentAsync(gs, filePath, deserializationOptions, cancellationToken);
}
- case (0x00, 0x00, 0xFE, 0xFF): // UTF-32 BE
- case (0xFF, 0xFE, 0x00, 0x00): // UTF-32 LE
+ case [0x00, 0x00, 0xFE, 0xFF]: // UTF-32 BE
+ case [0xFF, 0xFE, 0x00, 0x00]: // UTF-32 LE
{
using var sr = new StreamReader(stream, Encoding.UTF32);
- var jsonString = await sr.ReadToEndAsync();
+ var jsonString = await sr.ReadToEndAsync(cancellationToken);
return JsonDocument.Parse(jsonString.AsMemory(), deserializationOptions);
}
- case (0xFE, 0xFF, _, _): // UTF-16 BE
- case (0xFF, 0xFE, _, _): // UTF-16 LE
+ case [0xFE, 0xFF, ..]: // UTF-16 BE
+ case [0xFF, 0xFE, ..]: // UTF-16 LE
{
using var sr = new StreamReader(stream, Encoding.Unicode);
- var jsonString = await sr.ReadToEndAsync();
+ var jsonString = await sr.ReadToEndAsync(cancellationToken);
return JsonDocument.Parse(jsonString.AsMemory(), deserializationOptions);
}
- case (0xEF, 0xBB, 0xBF, _): // UTF-8
- case ((byte)'{', _, _, _): // Starts with a '{', probably JSON
+ case [0xEF, 0xBB, 0xBF, ..]: // UTF-8
+ case [(byte)'{', ..]: // Starts with a '{', probably JSON
{
return await JsonDocument.ParseAsync(stream, deserializationOptions, cancellationToken);
}
From 5283a4b82afc083e6515c9c7e356c538592570cd Mon Sep 17 00:00:00 2001
From: ScrubN <72096833+ScrubN@users.noreply.github.com>
Date: Sat, 8 Jun 2024 19:05:33 -0400
Subject: [PATCH 7/9] Use native OpenFolderDialog
---
TwitchDownloaderWPF/WindowQueueOptions.xaml.cs | 10 +++++++---
TwitchDownloaderWPF/WindowSettings.xaml.cs | 10 ++++++++--
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/TwitchDownloaderWPF/WindowQueueOptions.xaml.cs b/TwitchDownloaderWPF/WindowQueueOptions.xaml.cs
index 366265e7..f509ee19 100644
--- a/TwitchDownloaderWPF/WindowQueueOptions.xaml.cs
+++ b/TwitchDownloaderWPF/WindowQueueOptions.xaml.cs
@@ -5,6 +5,7 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
+using Microsoft.Win32;
using TwitchDownloaderCore.Options;
using TwitchDownloaderCore.Tools;
using TwitchDownloaderWPF.Properties;
@@ -625,12 +626,15 @@ private void EnqueueDataList()
private void btnFolder_Click(object sender, RoutedEventArgs e)
{
- var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
+ var dialog = new OpenFolderDialog();
if (Directory.Exists(textFolder.Text))
- dialog.RootFolder = dialog.RootFolder;
+ {
+ dialog.InitialDirectory = textFolder.Text;
+ }
+
if (dialog.ShowDialog(this).GetValueOrDefault())
{
- textFolder.Text = dialog.SelectedPath;
+ textFolder.Text = dialog.FolderName;
Settings.Default.QueueFolder = textFolder.Text;
Settings.Default.Save();
}
diff --git a/TwitchDownloaderWPF/WindowSettings.xaml.cs b/TwitchDownloaderWPF/WindowSettings.xaml.cs
index 6cfc8ecf..887f4eef 100644
--- a/TwitchDownloaderWPF/WindowSettings.xaml.cs
+++ b/TwitchDownloaderWPF/WindowSettings.xaml.cs
@@ -5,6 +5,7 @@
using System.Windows;
using System.Windows.Controls;
using HandyControl.Data;
+using Microsoft.Win32;
using TwitchDownloaderWPF.Models;
using TwitchDownloaderWPF.Properties;
using TwitchDownloaderWPF.Services;
@@ -28,10 +29,15 @@ public WindowSettings()
private void BtnTempBrowse_Click(object sender, RoutedEventArgs e)
{
- var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
+ var dialog = new OpenFolderDialog();
+ if (Directory.Exists(TextTempPath.Text))
+ {
+ dialog.InitialDirectory = TextTempPath.Text;
+ }
+
if (dialog.ShowDialog(this).GetValueOrDefault())
{
- TextTempPath.Text = dialog.SelectedPath;
+ TextTempPath.Text = dialog.FolderName;
}
}
From ccdd7522e3b0e582ad0d2418452ccc773404b03a Mon Sep 17 00:00:00 2001
From: ScrubN <72096833+ScrubN@users.noreply.github.com>
Date: Sat, 8 Jun 2024 19:24:24 -0400
Subject: [PATCH 8/9] Use native UnixFileMode
---
.../TwitchDownloaderCore.csproj | 1 -
TwitchDownloaderCore/TwitchHelper.cs | 20 +++++++++----------
2 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/TwitchDownloaderCore/TwitchDownloaderCore.csproj b/TwitchDownloaderCore/TwitchDownloaderCore.csproj
index 13f59391..6361a19f 100644
--- a/TwitchDownloaderCore/TwitchDownloaderCore.csproj
+++ b/TwitchDownloaderCore/TwitchDownloaderCore.csproj
@@ -25,7 +25,6 @@
-
diff --git a/TwitchDownloaderCore/TwitchHelper.cs b/TwitchDownloaderCore/TwitchHelper.cs
index ae992400..a2424a3d 100644
--- a/TwitchDownloaderCore/TwitchHelper.cs
+++ b/TwitchDownloaderCore/TwitchHelper.cs
@@ -888,7 +888,7 @@ public static FileInfo ClaimFile(string path, Func fileAlrea
return fileInfo;
}
- public static DirectoryInfo CreateDirectory(string path)
+ public static DirectoryInfo CreateDirectory(string path, ITaskLogger logger = null)
{
DirectoryInfo directoryInfo = Directory.CreateDirectory(path);
@@ -896,21 +896,21 @@ public static DirectoryInfo CreateDirectory(string path)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
- SetDirectoryPermissions(path);
+ directoryInfo.UnixFileMode = UnixFileMode.OtherExecute | UnixFileMode.OtherWrite | UnixFileMode.OtherRead
+ | UnixFileMode.GroupExecute | UnixFileMode.GroupWrite | UnixFileMode.GroupRead
+ | UnixFileMode.UserExecute | UnixFileMode.UserWrite | UnixFileMode.UserRead;
+
+ directoryInfo.Refresh();
}
}
- catch { }
+ catch (Exception e)
+ {
+ logger?.LogVerbose($"Failed to set unix file mode for {directoryInfo.FullName}: {e.Message}");
+ }
return directoryInfo;
}
- public static void SetDirectoryPermissions(string path)
- {
- var folderInfo = new Mono.Unix.UnixFileInfo(path);
- folderInfo.FileAccessPermissions = Mono.Unix.FileAccessPermissions.AllPermissions;
- folderInfo.Refresh();
- }
-
///
/// Cleans up any unmanaged cache files from previous runs that were interrupted before cleaning up
///
From c62dd703240ff23938a104437b48ed0c87f2cd50 Mon Sep 17 00:00:00 2001
From: ScrubN <72096833+ScrubN@users.noreply.github.com>
Date: Sat, 8 Jun 2024 19:30:49 -0400
Subject: [PATCH 9/9] Also use native UnixFileMode in CLI
---
TwitchDownloaderCLI/Modes/FfmpegHandler.cs | 9 ++-------
TwitchDownloaderCLI/TwitchDownloaderCLI.csproj | 1 -
TwitchDownloaderCore/TwitchHelper.cs | 18 +++++++++++++-----
3 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/TwitchDownloaderCLI/Modes/FfmpegHandler.cs b/TwitchDownloaderCLI/Modes/FfmpegHandler.cs
index 9feb2a05..4b6d44ce 100644
--- a/TwitchDownloaderCLI/Modes/FfmpegHandler.cs
+++ b/TwitchDownloaderCLI/Modes/FfmpegHandler.cs
@@ -4,9 +4,9 @@
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
-using Mono.Unix;
using TwitchDownloaderCLI.Modes.Arguments;
using TwitchDownloaderCLI.Tools;
+using TwitchDownloaderCore;
using TwitchDownloaderCore.Interfaces;
using Xabe.FFmpeg;
using Xabe.FFmpeg.Downloader;
@@ -49,12 +49,7 @@ private static void DownloadFfmpeg(ITaskProgress progress)
try
{
- var ffmpegFileInfo = new UnixFileInfo("ffmpeg")
- {
- FileAccessPermissions = FileAccessPermissions.UserRead | FileAccessPermissions.UserWrite | FileAccessPermissions.GroupRead | FileAccessPermissions.OtherRead |
- FileAccessPermissions.UserExecute | FileAccessPermissions.GroupExecute | FileAccessPermissions.OtherExecute
- };
- ffmpegFileInfo.Refresh();
+ TwitchHelper.Set777UnixFilePermissions(new FileInfo(FfmpegExecutableName));
}
catch
{
diff --git a/TwitchDownloaderCLI/TwitchDownloaderCLI.csproj b/TwitchDownloaderCLI/TwitchDownloaderCLI.csproj
index 15da5bab..04dbf704 100644
--- a/TwitchDownloaderCLI/TwitchDownloaderCLI.csproj
+++ b/TwitchDownloaderCLI/TwitchDownloaderCLI.csproj
@@ -14,7 +14,6 @@
-
diff --git a/TwitchDownloaderCore/TwitchHelper.cs b/TwitchDownloaderCore/TwitchHelper.cs
index a2424a3d..5410160c 100644
--- a/TwitchDownloaderCore/TwitchHelper.cs
+++ b/TwitchDownloaderCore/TwitchHelper.cs
@@ -9,6 +9,7 @@
using System.Net.Http;
using System.Net.Http.Json;
using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
@@ -896,11 +897,7 @@ public static DirectoryInfo CreateDirectory(string path, ITaskLogger logger = nu
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
- directoryInfo.UnixFileMode = UnixFileMode.OtherExecute | UnixFileMode.OtherWrite | UnixFileMode.OtherRead
- | UnixFileMode.GroupExecute | UnixFileMode.GroupWrite | UnixFileMode.GroupRead
- | UnixFileMode.UserExecute | UnixFileMode.UserWrite | UnixFileMode.UserRead;
-
- directoryInfo.Refresh();
+ Set777UnixFilePermissions(directoryInfo);
}
}
catch (Exception e)
@@ -911,6 +908,17 @@ public static DirectoryInfo CreateDirectory(string path, ITaskLogger logger = nu
return directoryInfo;
}
+ [UnsupportedOSPlatform("windows")]
+ public static FileSystemInfo Set777UnixFilePermissions(FileSystemInfo fileSystemInfo)
+ {
+ fileSystemInfo.UnixFileMode = UnixFileMode.OtherExecute | UnixFileMode.OtherWrite | UnixFileMode.OtherRead
+ | UnixFileMode.GroupExecute | UnixFileMode.GroupWrite | UnixFileMode.GroupRead
+ | UnixFileMode.UserExecute | UnixFileMode.UserWrite | UnixFileMode.UserRead;
+
+ fileSystemInfo.Refresh();
+ return fileSystemInfo;
+ }
+
///
/// Cleans up any unmanaged cache files from previous runs that were interrupted before cleaning up
///