diff --git a/WeddingShare.UnitTests/Tests/Helpers/DeviceDetector.cs b/WeddingShare.UnitTests/Tests/Helpers/DeviceDetector.cs new file mode 100644 index 0000000..9f7a8d0 --- /dev/null +++ b/WeddingShare.UnitTests/Tests/Helpers/DeviceDetector.cs @@ -0,0 +1,23 @@ +using WeddingShare.Enums; +using WeddingShare.Helpers; + +namespace WeddingShare.UnitTests.Tests.Helpers +{ + public class DeviceDetectorTests + { + [SetUp] + public void Setup() + { + } + + [TestCase("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36", DeviceType.Desktop)] + [TestCase("Mozilla/5.0 (Linux; Android 7.0; SM-T827R4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Safari/537.36", DeviceType.Tablet)] + [TestCase("Mozilla/5.0 (Linux; Android 13; SM-G998B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", DeviceType.Mobile)] + [TestCase("Googlebot-Image/1.0", DeviceType.Desktop)] + public async Task DeviceDetector_ParseDeviceType(string userAgent, DeviceType expected) + { + var actual = await new DeviceDetector().ParseDeviceType(userAgent); + Assert.That(actual, Is.EqualTo(expected)); + } + } +} \ No newline at end of file diff --git a/WeddingShare/Controllers/AdminController.cs b/WeddingShare/Controllers/AdminController.cs index 5c9a46e..f54e0d2 100644 --- a/WeddingShare/Controllers/AdminController.cs +++ b/WeddingShare/Controllers/AdminController.cs @@ -20,6 +20,7 @@ public class AdminController : Controller private readonly IWebHostEnvironment _hostingEnvironment; private readonly IConfigHelper _config; private readonly IDatabaseHelper _database; + private readonly IDeviceDetector _deviceDetector; private readonly IImageHelper _imageHelper; private readonly ILogger _logger; private readonly IStringLocalizer _localizer; @@ -27,11 +28,12 @@ public class AdminController : Controller private readonly string UploadsDirectory; private readonly string ThumbnailsDirectory; - public AdminController(IWebHostEnvironment hostingEnvironment, IConfigHelper config, IDatabaseHelper database, IImageHelper imageHelper, ILogger logger, IStringLocalizer localizer) + public AdminController(IWebHostEnvironment hostingEnvironment, IConfigHelper config, IDatabaseHelper database, IDeviceDetector deviceDetector, IImageHelper imageHelper, ILogger logger, IStringLocalizer localizer) { _hostingEnvironment = hostingEnvironment; _config = config; _database = database; + _deviceDetector = deviceDetector; _imageHelper = imageHelper; _logger = logger; _localizer = localizer; @@ -87,6 +89,13 @@ public async Task Index() var model = new IndexModel(); + var deviceType = HttpContext.Session.GetString("DeviceType"); + if (string.IsNullOrWhiteSpace(deviceType)) + { + deviceType = (await _deviceDetector.ParseDeviceType(Request.Headers["User-Agent"].ToString())).ToString(); + HttpContext.Session.SetString("DeviceType", deviceType ?? "Desktop"); + } + try { if (!_config.GetOrDefault("Settings", "Single_Gallery_Mode", false)) diff --git a/WeddingShare/Controllers/GalleryController.cs b/WeddingShare/Controllers/GalleryController.cs index 9b60c35..d9e4c8c 100644 --- a/WeddingShare/Controllers/GalleryController.cs +++ b/WeddingShare/Controllers/GalleryController.cs @@ -19,20 +19,20 @@ public class GalleryController : Controller private readonly IConfigHelper _config; private readonly IDatabaseHelper _database; private readonly ISecretKeyHelper _secretKey; - private readonly IMemoryCache _memoryCache; + private readonly IDeviceDetector _deviceDetector; private readonly ILogger _logger; private readonly IStringLocalizer _localizer; private readonly string UploadsDirectory; private readonly string ThumbnailsDirectory; - public GalleryController(IWebHostEnvironment hostingEnvironment, IConfigHelper config, IDatabaseHelper database, ISecretKeyHelper secretKey, IMemoryCache cache, ILogger logger, IStringLocalizer localizer) + public GalleryController(IWebHostEnvironment hostingEnvironment, IConfigHelper config, IDatabaseHelper database, ISecretKeyHelper secretKey, IDeviceDetector deviceDetector, ILogger logger, IStringLocalizer localizer) { _hostingEnvironment = hostingEnvironment; _config = config; _database = database; _secretKey = secretKey; - _memoryCache = cache; + _deviceDetector = deviceDetector; _logger = logger; _localizer = localizer; @@ -51,26 +51,14 @@ public async Task Index(string id = "default", string? key = null id = "default"; } - try + var deviceType = HttpContext.Session.GetString("DeviceType"); + if (string.IsNullOrWhiteSpace(deviceType)) { - var userAgent = Request.Headers["User-Agent"].ToString(); - if (!_memoryCache.TryGetValue(userAgent, out var isMobile)) - { - var dd = new DeviceDetectorNET.DeviceDetector(userAgent); - dd.Parse(); - - isMobile = dd.IsParsed() && dd.IsMobile(); - - _memoryCache.Set(userAgent, isMobile); - } - - ViewBag.IsMobile = isMobile; - } - catch - { - ViewBag.IsMobile = false; + deviceType = (await _deviceDetector.ParseDeviceType(Request.Headers["User-Agent"].ToString())).ToString(); + HttpContext.Session.SetString("DeviceType", deviceType ?? "Desktop"); } + ViewBag.IsMobile = !string.Equals("Desktop", deviceType, StringComparison.OrdinalIgnoreCase); ViewBag.SecretKey = key; var galleryPath = Path.Combine(UploadsDirectory, id); diff --git a/WeddingShare/Controllers/HomeController.cs b/WeddingShare/Controllers/HomeController.cs index b7540b5..b4bb058 100644 --- a/WeddingShare/Controllers/HomeController.cs +++ b/WeddingShare/Controllers/HomeController.cs @@ -7,15 +7,25 @@ namespace WeddingShare.Controllers [AllowAnonymous] public class HomeController : Controller { + private readonly IDeviceDetector _deviceDetector; private readonly ILogger _logger; - public HomeController(IConfigHelper config, ILogger logger) + + public HomeController(IDeviceDetector deviceDetector, ILogger logger) { + _deviceDetector = deviceDetector; _logger = logger; } [HttpGet] - public IActionResult Index() + public async Task Index() { + var deviceType = HttpContext.Session.GetString("DeviceType"); + if (string.IsNullOrWhiteSpace(deviceType)) + { + deviceType = (await _deviceDetector.ParseDeviceType(Request.Headers["User-Agent"].ToString())).ToString(); + HttpContext.Session.SetString("DeviceType", deviceType ?? "Desktop"); + } + return View(); } } diff --git a/WeddingShare/Enums/DeviceType.cs b/WeddingShare/Enums/DeviceType.cs new file mode 100644 index 0000000..92dba5b --- /dev/null +++ b/WeddingShare/Enums/DeviceType.cs @@ -0,0 +1,10 @@ +namespace WeddingShare.Enums +{ + public enum DeviceType + { + Unknown, + Desktop, + Tablet, + Mobile + } +} \ No newline at end of file diff --git a/WeddingShare/Helpers/Database/SQLiteDatabaseHelper.cs b/WeddingShare/Helpers/Database/SQLiteDatabaseHelper.cs index 3dca06c..e7520ab 100644 --- a/WeddingShare/Helpers/Database/SQLiteDatabaseHelper.cs +++ b/WeddingShare/Helpers/Database/SQLiteDatabaseHelper.cs @@ -1,10 +1,7 @@ using System.Data; -using System.Globalization; using Microsoft.Data.Sqlite; -using Mono.TextTemplating; using WeddingShare.Enums; using WeddingShare.Models.Database; -using YamlDotNet.Core.Tokens; namespace WeddingShare.Helpers.Database { diff --git a/WeddingShare/Helpers/DeviceDetector.cs b/WeddingShare/Helpers/DeviceDetector.cs new file mode 100644 index 0000000..2c81478 --- /dev/null +++ b/WeddingShare/Helpers/DeviceDetector.cs @@ -0,0 +1,36 @@ +using System.Text.RegularExpressions; +using WeddingShare.Enums; + +namespace WeddingShare.Helpers +{ + public interface IDeviceDetector + { + Task ParseDeviceType(string userAgent); + } + + public class DeviceDetector : IDeviceDetector + { + public async Task ParseDeviceType(string userAgent) + { + return await Task.Run(() => + { + if (string.IsNullOrEmpty(userAgent)) + { + return DeviceType.Unknown; + } + + if (Regex.IsMatch(userAgent, "(tablet|ipad|playbook|silk)|(android(?!.*mobile))", RegexOptions.IgnoreCase)) + { + return DeviceType.Tablet; + } + + if (Regex.IsMatch(userAgent, "blackberry|iphone|mobile|windows ce|opera mini|htc|sony|palm|symbianos|ipad|ipod|blackberry|bada|kindle|symbian|sonyericsson|android|samsung|nokia|wap|motor", RegexOptions.IgnoreCase)) + { + return DeviceType.Mobile; + } + + return DeviceType.Desktop; + }); + } + } +} \ No newline at end of file diff --git a/WeddingShare/Startup.cs b/WeddingShare/Startup.cs index 4814f02..4b96889 100644 --- a/WeddingShare/Startup.cs +++ b/WeddingShare/Startup.cs @@ -26,6 +26,7 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); var config = new ConfigHelper(new EnvironmentWrapper(), Configuration, _loggerFactory.CreateLogger()); switch (config.GetOrDefault("Database", "Database_Type", "sqlite")?.ToLower()) @@ -95,6 +96,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseAuthentication(); app.UseAuthorization(); app.UseRequestLocalization(); + app.UseSession(); app.UseEndpoints(endpoints => { diff --git a/WeddingShare/WeddingShare.csproj b/WeddingShare/WeddingShare.csproj index aed63ba..6b6027c 100644 --- a/WeddingShare/WeddingShare.csproj +++ b/WeddingShare/WeddingShare.csproj @@ -18,7 +18,6 @@ - diff --git a/WeddingShare/appsettings.json b/WeddingShare/appsettings.json index f225e56..c8cb71a 100644 --- a/WeddingShare/appsettings.json +++ b/WeddingShare/appsettings.json @@ -34,7 +34,7 @@ "Directory_Scanner_Interval": "*/30 * * * *" }, "Release": { - "Version": "1.1.1" + "Version": "1.1.2" }, "AllowedHosts": "*" } \ No newline at end of file