using System; using System.Net.Http; using System.Text; using System.Threading.Tasks; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; namespace NFOGuard.Emby.Plugin { public class LicenseManager { private readonly ILogger _logger; private readonly HttpClient _httpClient; private const string NFOGUARD_API_URL = "https://nfoguard.com/api"; // Your future API endpoint public LicenseManager(ILogger logger) { _logger = logger; _httpClient = new HttpClient(); _httpClient.Timeout = TimeSpan.FromSeconds(10); // Quick timeout for license checks } public async Task CheckLicenseStatusAsync() { try { var config = Plugin.Instance.Configuration; // Get unique identifier for this installation var machineId = GetMachineIdentifier(); _logger.Info("NFOGuard :: Checking automatic license status..."); // Check Patreon subscription var patreonValid = await CheckPatreonSubscriptionAsync(machineId); if (patreonValid) { _logger.Info("NFOGuard :: Valid Patreon subscription found"); return true; } // Check PayPal recurring payment var paypalValid = await CheckPayPalSubscriptionAsync(machineId); if (paypalValid) { _logger.Info("NFOGuard :: Valid PayPal subscription found"); return true; } _logger.Info("NFOGuard :: No active subscription found, using free tier"); return false; } catch (Exception ex) { _logger.ErrorException("NFOGuard :: License validation error", ex); return false; // Default to free tier on error } } private async Task CheckPatreonSubscriptionAsync(string machineId) { try { var requestUrl = $"{NFOGUARD_API_URL}/patreon/check?machine_id={machineId}"; var response = await _httpClient.GetStringAsync(requestUrl); // Parse response (you'll implement the API to return JSON like {"active": true, "tier": "supporter"}) return response.Contains("\"active\":true"); } catch (HttpRequestException) { _logger.Info("NFOGuard :: Cannot reach license server, running in offline mode"); return false; // Offline mode - use free tier } catch (Exception ex) { _logger.ErrorException("NFOGuard :: Patreon check error", ex); return false; } } private async Task CheckPayPalSubscriptionAsync(string machineId) { try { var requestUrl = $"{NFOGUARD_API_URL}/paypal/check?machine_id={machineId}"; var response = await _httpClient.GetStringAsync(requestUrl); // Parse response return response.Contains("\"active\":true"); } catch (HttpRequestException) { _logger.Info("NFOGuard :: Cannot reach license server, running in offline mode"); return false; } catch (Exception ex) { _logger.ErrorException("NFOGuard :: PayPal check error", ex); return false; } } public string GetMachineIdentifier() { try { // Create a unique but consistent identifier for this installation // Combine multiple factors to create a stable machine ID var machineName = Environment.MachineName ?? "unknown"; var userDomain = Environment.UserDomainName ?? "unknown"; var installPath = Plugin.Instance.ConfigurationFilePath; var combined = $"{machineName}-{userDomain}-{installPath}".GetHashCode().ToString("X8"); _logger.Info($"NFOGuard :: Machine ID: {combined}"); return combined; } catch (Exception ex) { _logger.ErrorException("NFOGuard :: Error generating machine ID", ex); return "FALLBACK-ID"; } } public bool IsTrialExpired() { // Implement trial logic here // For example, check installation date vs current date var installDate = Plugin.Instance.Configuration.InstallDate; if (installDate == DateTime.MinValue) { Plugin.Instance.Configuration.InstallDate = DateTime.UtcNow; Plugin.Instance.SaveConfiguration(); return false; } var trialDays = 30; // 30-day trial return DateTime.UtcNow > installDate.AddDays(trialDays); } public bool CanUseFeature() { // Check if license is valid or trial is still active return Plugin.Instance.Configuration.LicenseValid || !IsTrialExpired(); } public async Task CheckAndActivateLicenseAsync() { try { _logger.Info("NFOGuard :: Checking for active subscriptions..."); var isValid = await CheckLicenseStatusAsync(); var config = Plugin.Instance.Configuration; if (isValid && !config.LicenseValid) { // Activate license config.LicenseValid = true; config.MonthlyProcessingLimit = 0; // Remove limits config.ProcessedThisMonth = 0; // Reset counter Plugin.Instance.SaveConfiguration(); var freeTierManager = new FreeTierManager(_logger); freeTierManager.EnableFullVersion(); _logger.Info("NFOGuard :: Subscription detected - unlimited processing activated!"); return true; } else if (!isValid && config.LicenseValid) { // Deactivate license config.LicenseValid = false; Plugin.Instance.SaveConfiguration(); var freeTierManager = new FreeTierManager(_logger); freeTierManager.SetPercentageBasedLimits(); _logger.Info("NFOGuard :: No active subscription found - switched to free tier"); return false; } return isValid; } catch (Exception ex) { _logger.ErrorException("NFOGuard :: License check error", ex); return false; } } public async Task RegisterMachineAsync(string userEmail) { try { var machineId = GetMachineIdentifier(); var config = Plugin.Instance.Configuration; var registrationData = new { machine_id = machineId, email = userEmail, emby_version = Environment.OSVersion.ToString(), plugin_version = Plugin.Instance.Description, install_date = config.InstallDate.ToString("yyyy-MM-dd"), library_stats = GetLibraryStats() }; var json = System.Text.Json.JsonSerializer.Serialize(registrationData); var content = new StringContent(json, Encoding.UTF8, "application/json"); var response = await _httpClient.PostAsync($"{NFOGUARD_API_URL}/register", content); var responseText = await response.Content.ReadAsStringAsync(); if (response.IsSuccessStatusCode) { _logger.Info($"NFOGuard :: Machine registered successfully: {machineId}"); return $"Registration successful!\n\nMachine ID: {machineId}\n\nTo activate unlimited processing:\n• Subscribe on Patreon: https://patreon.com/nfoguard\n• Or PayPal recurring: https://nfoguard.com/paypal\n\nThe plugin will automatically detect your subscription within 24 hours."; } else { _logger.Warn($"NFOGuard :: Registration failed: {responseText}"); return $"Registration failed. You can still use the free tier.\n\nMachine ID: {machineId}\nError: {responseText}"; } } catch (Exception ex) { _logger.ErrorException("NFOGuard :: Registration error", ex); var machineId = GetMachineIdentifier(); return $"Registration failed (offline mode).\n\nMachine ID: {machineId}\n\nTo activate later, visit: https://nfoguard.com/register"; } } private object GetLibraryStats() { try { // This would be used for analytics (anonymized) return new { episodes_estimated = "unknown", movies_estimated = "unknown", free_tier_usage = Plugin.Instance.Configuration.ProcessedThisMonth }; } catch { return new { error = "stats_unavailable" }; } } public void DeactivateLicense() { try { var config = Plugin.Instance.Configuration; config.LicenseValid = false; // Reset to percentage-based free tier var freeTierManager = new FreeTierManager(_logger); freeTierManager.SetPercentageBasedLimits(); Plugin.Instance.SaveConfiguration(); _logger.Info("NFOGuard :: License deactivated - switched to free tier"); } catch (Exception ex) { _logger.ErrorException("NFOGuard :: License deactivation error", ex); } } } }