mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-09-27 21:01:36 +00:00
Add support for Telegram Sticker (.tgs) files (#1762)
This commit is contained in:
@@ -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<Dictionary<string, object>>(jsonString);
|
||||
|
||||
|
@@ -0,0 +1,42 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
using QuickLook.Plugin.ImageViewer.Webview.Lottie;
|
||||
|
||||
namespace QuickLook.Plugin.ImageViewer.Webview.Tgs;
|
||||
|
||||
internal static class TgsDetector
|
||||
{
|
||||
public static bool IsValidFile(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Extract JSON content from gzipped TGS file
|
||||
var jsonString = TgsExtractor.GetJsonContent(path);
|
||||
return IsVaildContent(jsonString);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If any exception occurs, assume it's not a valid TGS file
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsVaildContent(string jsonString)
|
||||
=> LottieDetector.IsVaildContent(jsonString);
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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<string> GetPath()
|
||||
{
|
||||
return await Task.FromResult(new Uri(Path).AbsolutePath);
|
||||
}
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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<Dictionary<string, object>>(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);
|
||||
}
|
||||
}
|
@@ -20,6 +20,7 @@ using QuickLook.Common.Plugin;
|
||||
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;
|
||||
@@ -37,7 +38,8 @@ internal static class WebHandler
|
||||
{
|
||||
".svg" => SettingHelper.Get("RenderSvgWeb", true, "QuickLook.Plugin.ImageViewer"),
|
||||
".svga" or ".lottie" => true,
|
||||
".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,
|
||||
};
|
||||
}
|
||||
@@ -47,7 +49,7 @@ internal static class WebHandler
|
||||
string ext = Path.GetExtension(path).ToLower();
|
||||
|
||||
if (ext == ".svg" || ext == ".svga"
|
||||
|| ext == ".lottie" || ext == ".json")
|
||||
|| ext == ".lottie" || ext == ".tgs" || ext == ".json")
|
||||
{
|
||||
if (ext == ".svg")
|
||||
{
|
||||
@@ -63,6 +65,7 @@ internal static class WebHandler
|
||||
".svg" => new SvgMetaProvider(path),
|
||||
".svga" => new SvgaMetaProvider(path),
|
||||
".lottie" or ".json" => new LottieMetaProvider(path),
|
||||
".tgs" => new TgsMetaProvider(path),
|
||||
_ => throw new NotSupportedException($"Unsupported file type: {ext}")
|
||||
};
|
||||
var sizeSvg = metaWeb.GetSize();
|
||||
@@ -85,7 +88,8 @@ internal static class WebHandler
|
||||
string ext = Path.GetExtension(path).ToLower();
|
||||
|
||||
if (ext == ".svg" || ext == ".svga"
|
||||
|| ext == ".lottie" || ext == ".json")
|
||||
|| ext == ".lottie" || ext == ".json"
|
||||
|| ext == ".tgs")
|
||||
{
|
||||
if (ext == ".svg")
|
||||
{
|
||||
@@ -101,6 +105,7 @@ internal static class WebHandler
|
||||
".svg" => new SvgImagePanel(),
|
||||
".svga" => new SvgaImagePanel(metaWeb),
|
||||
".lottie" or ".json" => new LottieImagePanel(),
|
||||
".tgs" => new TgsImagePanel(),
|
||||
_ => throw new NotSupportedException($"Unsupported file type: {ext}")
|
||||
};
|
||||
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user