From dd04a18c2c37d8c8cf89a7a39c265098685dce92 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Sep 2025 17:04:27 +0000 Subject: [PATCH 1/6] Initial plan From e7a65387b5b0c10e92508977109aa6e7680dc5f7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Sep 2025 17:09:05 +0000 Subject: [PATCH 2/6] Implement TGS support for Telegram stickers Co-authored-by: emako <24737061+emako@users.noreply.github.com> --- .../Webview/Lottie/LottieDetector.cs | 13 +++++++- .../Webview/Lottie/LottieExtractor.cs | 9 +++++ .../Webview/Lottie/TgsExtractor.cs | 33 +++++++++++++++++++ .../Webview/WebHandler.cs | 10 +++--- 4 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/TgsExtractor.cs diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieDetector.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieDetector.cs index 6271b01ec..c02d79bf4 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieDetector.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieDetector.cs @@ -26,7 +26,18 @@ public static bool IsVaild(string path) { try { - var jsonString = File.ReadAllText(path); + string jsonString; + var ext = Path.GetExtension(path).ToLower(); + + if (ext == ".tgs") + { + // TGS files are gzipped Lottie JSON files + jsonString = TgsExtractor.GetJsonContent(path); + } + else + { + jsonString = File.ReadAllText(path); + } // No exception will be thrown here var jsonLottie = LottieParser.Parse>(jsonString); diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieExtractor.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieExtractor.cs index 92280d0b1..eea0ca405 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieExtractor.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieExtractor.cs @@ -27,6 +27,15 @@ internal static class LottieExtractor { public static string GetJsonContent(string path) { + var ext = Path.GetExtension(path).ToLower(); + + if (ext == ".tgs") + { + // TGS files are gzipped Lottie JSON files + return TgsExtractor.GetJsonContent(path); + } + + // Handle .lottie files (ZIP archives) using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); using var zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read); diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/TgsExtractor.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/TgsExtractor.cs new file mode 100644 index 000000000..af27d15e1 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/TgsExtractor.cs @@ -0,0 +1,33 @@ +// Copyright © 2017-2025 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.IO; +using System.IO.Compression; +using System.Text; + +namespace QuickLook.Plugin.ImageViewer.Webview.Lottie; + +internal static class TgsExtractor +{ + public static string GetJsonContent(string path) + { + using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); + using var gzipStream = new GZipStream(fileStream, CompressionMode.Decompress); + using var reader = new StreamReader(gzipStream, Encoding.UTF8); + return reader.ReadToEnd(); + } +} \ No newline at end of file diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/WebHandler.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/WebHandler.cs index e38a3660a..1f2d7bb4b 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/WebHandler.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/WebHandler.cs @@ -36,7 +36,7 @@ public static bool TryCanHandle(string path) return Path.GetExtension(path).ToLower() switch { ".svg" => SettingHelper.Get("RenderSvgWeb", true, "QuickLook.Plugin.ImageViewer"), - ".svga" or ".lottie" => true, + ".svga" or ".lottie" or ".tgs" => true, ".json" => LottieDetector.IsVaild(path), // Check for Lottie files _ => false, }; @@ -47,7 +47,7 @@ public static bool TryPrepare(string path, ContextObject context, out IWebMetaPr string ext = Path.GetExtension(path).ToLower(); if (ext == ".svg" || ext == ".svga" - || ext == ".lottie" || ext == ".json") + || ext == ".lottie" || ext == ".tgs" || ext == ".json") { if (ext == ".svg") { @@ -62,7 +62,7 @@ public static bool TryPrepare(string path, ContextObject context, out IWebMetaPr { ".svg" => new SvgMetaProvider(path), ".svga" => new SvgaMetaProvider(path), - ".lottie" or ".json" => new LottieMetaProvider(path), + ".lottie" or ".tgs" or ".json" => new LottieMetaProvider(path), _ => throw new NotSupportedException($"Unsupported file type: {ext}") }; var sizeSvg = metaWeb.GetSize(); @@ -85,7 +85,7 @@ public static bool TryView(string path, ContextObject context, IWebMetaProvider string ext = Path.GetExtension(path).ToLower(); if (ext == ".svg" || ext == ".svga" - || ext == ".lottie" || ext == ".json") + || ext == ".lottie" || ext == ".tgs" || ext == ".json") { if (ext == ".svg") { @@ -100,7 +100,7 @@ public static bool TryView(string path, ContextObject context, IWebMetaProvider { ".svg" => new SvgImagePanel(), ".svga" => new SvgaImagePanel(metaWeb), - ".lottie" or ".json" => new LottieImagePanel(), + ".lottie" or ".tgs" or ".json" => new LottieImagePanel(), _ => throw new NotSupportedException($"Unsupported file type: {ext}") }; From 2ca513f2ab735154f220671535104ac6d6908f82 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Sep 2025 17:12:18 +0000 Subject: [PATCH 3/6] Update documentation to include TGS and Lottie formats Co-authored-by: emako <24737061+emako@users.noreply.github.com> --- SUPPORTED_FORMATS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/SUPPORTED_FORMATS.md b/SUPPORTED_FORMATS.md index 67412b9e7..a0c1c14f5 100644 --- a/SUPPORTED_FORMATS.md +++ b/SUPPORTED_FORMATS.md @@ -37,6 +37,7 @@ - `.jxl` (JPEG XL) - `.jxr` (JPEG XR) - `.k25`, `.kdc` (Kodak RAW image) +- `.lottie` (Lottie animation) - `.mdc` (MagicDraw UML) - `.mef` (Mamiya RAW image) - `.mos` (Leaf RAW image) @@ -60,7 +61,9 @@ - `.rw2`, `.rwl`, `.rwz` (Panasonic/Leica RAW image) - `.sr2`, `.srf`, `.srw` (Sony RAW image) - `.svg`, `.svgz` (Scalable Vector Graphics) +- `.svga` (SVGA animation) - `.tga` (Truevision TGA) +- `.tgs` (Telegram sticker, Lottie animation) - `.tif`, `.tiff` (Tagged Image File Format) - `.wdp` (Windows Media Photo) - `.webp` (WebP image) From 0b0e9e9a7afcc02f2e9bc46d7c1c9c2cda19cc0f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Sep 2025 20:27:55 +0000 Subject: [PATCH 4/6] Refactor TGS support into separate Tgs folder structure Co-authored-by: emako <24737061+emako@users.noreply.github.com> --- .../Webview/Lottie/LottieDetector.cs | 13 +-- .../Webview/Lottie/LottieExtractor.cs | 9 -- .../Webview/Tgs/TgsDetector.cs | 53 +++++++++++ .../Webview/Tgs/TgsExtractor.cs | 33 +++++++ .../Webview/Tgs/TgsImagePanel.cs | 92 +++++++++++++++++++ .../Webview/Tgs/TgsMetaProvider.cs | 62 +++++++++++++ .../Webview/WebHandler.cs | 10 +- 7 files changed, 248 insertions(+), 24 deletions(-) create mode 100644 QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsDetector.cs create mode 100644 QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsExtractor.cs create mode 100644 QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsImagePanel.cs create mode 100644 QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsMetaProvider.cs diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieDetector.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieDetector.cs index c02d79bf4..6271b01ec 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieDetector.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieDetector.cs @@ -26,18 +26,7 @@ public static bool IsVaild(string path) { try { - string jsonString; - var ext = Path.GetExtension(path).ToLower(); - - if (ext == ".tgs") - { - // TGS files are gzipped Lottie JSON files - jsonString = TgsExtractor.GetJsonContent(path); - } - else - { - jsonString = File.ReadAllText(path); - } + var jsonString = File.ReadAllText(path); // No exception will be thrown here var jsonLottie = LottieParser.Parse>(jsonString); diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieExtractor.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieExtractor.cs index eea0ca405..92280d0b1 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieExtractor.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieExtractor.cs @@ -27,15 +27,6 @@ internal static class LottieExtractor { public static string GetJsonContent(string path) { - var ext = Path.GetExtension(path).ToLower(); - - if (ext == ".tgs") - { - // TGS files are gzipped Lottie JSON files - return TgsExtractor.GetJsonContent(path); - } - - // Handle .lottie files (ZIP archives) using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); using var zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read); diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsDetector.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsDetector.cs new file mode 100644 index 000000000..0ede8c4c9 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsDetector.cs @@ -0,0 +1,53 @@ +// Copyright © 2017-2025 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using QuickLook.Plugin.ImageViewer.Webview.Lottie; +using System.Collections.Generic; +using System.IO; + +namespace QuickLook.Plugin.ImageViewer.Webview.Tgs; + +internal static class TgsDetector +{ + public static bool IsValid(string path) + { + try + { + // Extract JSON content from gzipped TGS file + var jsonString = TgsExtractor.GetJsonContent(path); + + // Use Lottie parser to validate the JSON structure + var jsonLottie = LottieParser.Parse>(jsonString); + + if (jsonLottie != null + && jsonLottie.ContainsKey("v") + && jsonLottie.ContainsKey("fr") + && jsonLottie.ContainsKey("ip") + && jsonLottie.ContainsKey("op") + && jsonLottie.ContainsKey("layers")) + { + return true; + } + } + catch + { + // If any exception occurs, assume it's not a valid TGS file + } + + return false; + } +} \ No newline at end of file diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsExtractor.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsExtractor.cs new file mode 100644 index 000000000..1a43ba1a7 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsExtractor.cs @@ -0,0 +1,33 @@ +// Copyright © 2017-2025 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.IO; +using System.IO.Compression; +using System.Text; + +namespace QuickLook.Plugin.ImageViewer.Webview.Tgs; + +internal static class TgsExtractor +{ + public static string GetJsonContent(string path) + { + using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); + using var gzipStream = new GZipStream(fileStream, CompressionMode.Decompress); + using var reader = new StreamReader(gzipStream, Encoding.UTF8); + return reader.ReadToEnd(); + } +} \ No newline at end of file diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsImagePanel.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsImagePanel.cs new file mode 100644 index 000000000..74501aa64 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsImagePanel.cs @@ -0,0 +1,92 @@ +// Copyright © 2017-2025 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using Microsoft.Web.WebView2.Core; +using QuickLook.Plugin.ImageViewer.Webview.Svg; +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace QuickLook.Plugin.ImageViewer.Webview.Tgs; + +public class TgsImagePanel : SvgImagePanel +{ + public override void Preview(string path) + { + FallbackPath = Path.GetDirectoryName(path); + + ObjectForScripting ??= new TgsScriptHandler(path); + + _homePage = _resources["/lottie2html.html"]; + NavigateToUri(new Uri("file://quicklook/")); + } + + protected override void WebView_WebResourceRequested(object sender, CoreWebView2WebResourceRequestedEventArgs args) + { + try + { + var requestedUri = new Uri(args.Request.Uri); + + if ((requestedUri.Scheme == "https" || requestedUri.Scheme == "http") + && requestedUri.AbsolutePath.EndsWith(".tgs", StringComparison.OrdinalIgnoreCase)) + { + var localPath = Uri.UnescapeDataString($"{requestedUri.Authority}:{requestedUri.AbsolutePath}".Replace('/', '\\')); + + if (localPath.StartsWith(_fallbackPath, StringComparison.OrdinalIgnoreCase)) + { + if (File.Exists(localPath)) + { + var content = TgsExtractor.GetJsonContent(localPath); + byte[] byteArray = Encoding.UTF8.GetBytes(content); + var stream = new MemoryStream(byteArray); + var response = _webView.CoreWebView2.Environment.CreateWebResourceResponse( + stream, 200, "OK", + $""" + Access-Control-Allow-Origin: * + Content-Type: {MimeTypes.GetMimeType()} + """ + ); + args.Response = response; + return; + } + } + } + } + catch (Exception e) + { + // We don't need to feel burdened by any exceptions + Debug.WriteLine(e); + } + + base.WebView_WebResourceRequested(sender, args); + } +} + +[ClassInterface(ClassInterfaceType.AutoDual)] +[ComVisible(true)] +public sealed class TgsScriptHandler(string path) +{ + public string Path { get; } = path; + + public async Task GetPath() + { + return await Task.FromResult(new Uri(Path).AbsolutePath); + } +} \ No newline at end of file diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsMetaProvider.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsMetaProvider.cs new file mode 100644 index 000000000..9a62e003b --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsMetaProvider.cs @@ -0,0 +1,62 @@ +// Copyright © 2017-2025 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using QuickLook.Plugin.ImageViewer.Webview.Lottie; +using System.Collections.Generic; +using System.IO; +using System.Windows; + +namespace QuickLook.Plugin.ImageViewer.Webview.Tgs; + +public class TgsMetaProvider(string path) : IWebMetaProvider +{ + private readonly string _path = path; + private Size _size = Size.Empty; + + public Size GetSize() + { + if (_size != Size.Empty) + { + return _size; + } + + if (!File.Exists(_path)) + { + return _size; + } + + try + { + var jsonString = TgsExtractor.GetJsonContent(_path); + var jsonLottie = LottieParser.Parse>(jsonString); + + if (jsonLottie.ContainsKey("w") + && jsonLottie.ContainsKey("h") + && double.TryParse(jsonLottie["w"].ToString(), out double width) + && double.TryParse(jsonLottie["h"].ToString(), out double height)) + { + return _size = new Size(width, height); + } + } + catch + { + // That's fine, just return the default size. + } + + return new Size(800, 600); + } +} \ No newline at end of file diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/WebHandler.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/WebHandler.cs index 1f2d7bb4b..d6bdc00fa 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/WebHandler.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/WebHandler.cs @@ -20,6 +20,7 @@ using QuickLook.Plugin.ImageViewer.Webview.Lottie; using QuickLook.Plugin.ImageViewer.Webview.Svg; using QuickLook.Plugin.ImageViewer.Webview.Svga; +using QuickLook.Plugin.ImageViewer.Webview.Tgs; using System; using System.IO; using System.Windows; @@ -36,7 +37,8 @@ public static bool TryCanHandle(string path) return Path.GetExtension(path).ToLower() switch { ".svg" => SettingHelper.Get("RenderSvgWeb", true, "QuickLook.Plugin.ImageViewer"), - ".svga" or ".lottie" or ".tgs" => true, + ".svga" or ".lottie" => true, + ".tgs" => TgsDetector.IsValid(path), // Check for TGS files ".json" => LottieDetector.IsVaild(path), // Check for Lottie files _ => false, }; @@ -62,7 +64,8 @@ public static bool TryPrepare(string path, ContextObject context, out IWebMetaPr { ".svg" => new SvgMetaProvider(path), ".svga" => new SvgaMetaProvider(path), - ".lottie" or ".tgs" or ".json" => new LottieMetaProvider(path), + ".lottie" or ".json" => new LottieMetaProvider(path), + ".tgs" => new TgsMetaProvider(path), _ => throw new NotSupportedException($"Unsupported file type: {ext}") }; var sizeSvg = metaWeb.GetSize(); @@ -100,7 +103,8 @@ public static bool TryView(string path, ContextObject context, IWebMetaProvider { ".svg" => new SvgImagePanel(), ".svga" => new SvgaImagePanel(metaWeb), - ".lottie" or ".tgs" or ".json" => new LottieImagePanel(), + ".lottie" or ".json" => new LottieImagePanel(), + ".tgs" => new TgsImagePanel(), _ => throw new NotSupportedException($"Unsupported file type: {ext}") }; From cafd2413be937ae330b3e83ee10669bd7830a5d1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Sep 2025 20:47:00 +0000 Subject: [PATCH 5/6] Remove TgsExtractor.cs from Lottie folder Co-authored-by: emako <24737061+emako@users.noreply.github.com> --- .../Webview/Lottie/TgsExtractor.cs | 33 ------------------- 1 file changed, 33 deletions(-) delete mode 100644 QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/TgsExtractor.cs diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/TgsExtractor.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/TgsExtractor.cs deleted file mode 100644 index af27d15e1..000000000 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/TgsExtractor.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright © 2017-2025 QL-Win Contributors -// -// This file is part of QuickLook program. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -using System.IO; -using System.IO.Compression; -using System.Text; - -namespace QuickLook.Plugin.ImageViewer.Webview.Lottie; - -internal static class TgsExtractor -{ - public static string GetJsonContent(string path) - { - using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); - using var gzipStream = new GZipStream(fileStream, CompressionMode.Decompress); - using var reader = new StreamReader(gzipStream, Encoding.UTF8); - return reader.ReadToEnd(); - } -} \ No newline at end of file From e4e014d9d76906e9301179607f8de446693b3947 Mon Sep 17 00:00:00 2001 From: ema Date: Mon, 22 Sep 2025 04:56:16 +0800 Subject: [PATCH 6/6] Refactor Lottie and TGS file validation methods Renamed and split validation methods for Lottie and TGS files to improve clarity and code reuse. Added IsVaildContent for both detectors and updated WebHandler to use the new method names. --- .../Webview/Lottie/LottieDetector.cs | 15 +++++++++++- .../Webview/Tgs/TgsDetector.cs | 23 +++++-------------- .../Webview/Tgs/TgsExtractor.cs | 2 +- .../Webview/Tgs/TgsImagePanel.cs | 2 +- .../Webview/Tgs/TgsMetaProvider.cs | 2 +- .../Webview/WebHandler.cs | 7 +++--- 6 files changed, 27 insertions(+), 24 deletions(-) diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieDetector.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieDetector.cs index 6271b01ec..70d3cf7f5 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieDetector.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Lottie/LottieDetector.cs @@ -22,12 +22,25 @@ namespace QuickLook.Plugin.ImageViewer.Webview.Lottie; internal static class LottieDetector { - public static bool IsVaild(string path) + public static bool IsVaildFile(string path) { try { var jsonString = File.ReadAllText(path); + return IsVaildContent(jsonString); + } + catch + { + // If any exception occurs, assume it's not a valid Lottie file + } + return false; + } + + public static bool IsVaildContent(string jsonString) + { + try + { // No exception will be thrown here var jsonLottie = LottieParser.Parse>(jsonString); diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsDetector.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsDetector.cs index 0ede8c4c9..c741667df 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsDetector.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsDetector.cs @@ -16,32 +16,18 @@ // along with this program. If not, see . using QuickLook.Plugin.ImageViewer.Webview.Lottie; -using System.Collections.Generic; -using System.IO; namespace QuickLook.Plugin.ImageViewer.Webview.Tgs; internal static class TgsDetector { - public static bool IsValid(string path) + public static bool IsValidFile(string path) { try { // Extract JSON content from gzipped TGS file var jsonString = TgsExtractor.GetJsonContent(path); - - // Use Lottie parser to validate the JSON structure - var jsonLottie = LottieParser.Parse>(jsonString); - - if (jsonLottie != null - && jsonLottie.ContainsKey("v") - && jsonLottie.ContainsKey("fr") - && jsonLottie.ContainsKey("ip") - && jsonLottie.ContainsKey("op") - && jsonLottie.ContainsKey("layers")) - { - return true; - } + return IsVaildContent(jsonString); } catch { @@ -50,4 +36,7 @@ public static bool IsValid(string path) return false; } -} \ No newline at end of file + + public static bool IsVaildContent(string jsonString) + => LottieDetector.IsVaildContent(jsonString); +} diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsExtractor.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsExtractor.cs index 1a43ba1a7..df98f2221 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsExtractor.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsExtractor.cs @@ -30,4 +30,4 @@ public static string GetJsonContent(string path) using var reader = new StreamReader(gzipStream, Encoding.UTF8); return reader.ReadToEnd(); } -} \ No newline at end of file +} diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsImagePanel.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsImagePanel.cs index 74501aa64..10da24db9 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsImagePanel.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsImagePanel.cs @@ -89,4 +89,4 @@ public async Task GetPath() { return await Task.FromResult(new Uri(Path).AbsolutePath); } -} \ No newline at end of file +} diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsMetaProvider.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsMetaProvider.cs index 9a62e003b..7b51e4a54 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsMetaProvider.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/Tgs/TgsMetaProvider.cs @@ -59,4 +59,4 @@ public Size GetSize() return new Size(800, 600); } -} \ No newline at end of file +} diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/WebHandler.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/WebHandler.cs index d6bdc00fa..bc6487cb9 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/WebHandler.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Webview/WebHandler.cs @@ -38,8 +38,8 @@ public static bool TryCanHandle(string path) { ".svg" => SettingHelper.Get("RenderSvgWeb", true, "QuickLook.Plugin.ImageViewer"), ".svga" or ".lottie" => true, - ".tgs" => TgsDetector.IsValid(path), // Check for TGS files - ".json" => LottieDetector.IsVaild(path), // Check for Lottie files + ".tgs" => TgsDetector.IsValidFile(path), // Check for TGS files + ".json" => LottieDetector.IsVaildFile(path), // Check for Lottie files _ => false, }; } @@ -88,7 +88,8 @@ public static bool TryView(string path, ContextObject context, IWebMetaProvider string ext = Path.GetExtension(path).ToLower(); if (ext == ".svg" || ext == ".svga" - || ext == ".lottie" || ext == ".tgs" || ext == ".json") + || ext == ".lottie" || ext == ".json" + || ext == ".tgs") { if (ext == ".svg") {