Skip to content

Commit a895e55

Browse files
committed
Fixed first run issues
- Fixed first run issues where the exe wouldn't run with certain files missing - Added a log to help diagnose these issues in the future - Create appsettings.json file after first run 1. First Run: Creates appsettings.json in AppData with version 2.1.0 2. Subsequent Runs: Loads config from AppData 3. Version Mismatch: Automatically updates config version to match exe 4. Missing Config: Creates new one with proper defaults 5. All Errors: Logged to %APPDATA%\IPTV-Desktop-Browser\Logs\
1 parent d90ddf6 commit a895e55

File tree

6 files changed

+515
-36
lines changed

6 files changed

+515
-36
lines changed

DesktopApp/App.xaml.cs

Lines changed: 150 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,42 +9,154 @@
99
using Microsoft.Extensions.DependencyInjection;
1010
using Microsoft.Extensions.Hosting;
1111
using Microsoft.Extensions.Logging;
12+
using Serilog;
13+
using System.Windows.Threading;
1214

1315
namespace DesktopApp;
1416

1517
public partial class App : Application
1618
{
1719
private IHost? _host;
1820

21+
public App()
22+
{
23+
// Set up global exception handlers
24+
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
25+
DispatcherUnhandledException += OnDispatcherUnhandledException;
26+
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
27+
}
28+
1929
protected override void OnStartup(StartupEventArgs e)
2030
{
21-
// Configure dependency injection
22-
_host = CreateHostBuilder().Build();
31+
try
32+
{
33+
// Initialize logging first
34+
var logPath = Path.Combine(
35+
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
36+
"IPTV-Desktop-Browser",
37+
"Logs",
38+
"app-.log"
39+
);
40+
41+
Log.Logger = new LoggerConfiguration()
42+
.MinimumLevel.Information()
43+
.WriteTo.File(
44+
logPath,
45+
rollingInterval: RollingInterval.Day,
46+
retainedFileCountLimit: 7,
47+
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
48+
)
49+
.CreateLogger();
50+
51+
Log.Information("=== Application Starting ===");
52+
Log.Information("Version: {Version}", "2.1.0");
53+
Log.Information("OS: {OS}", Environment.OSVersion);
54+
Log.Information(".NET Version: {DotNetVersion}", Environment.Version);
55+
56+
// Configure dependency injection
57+
_host = CreateHostBuilder().Build();
58+
59+
// Initialize Session with configuration settings
60+
var apiSettings = _host.Services.GetRequiredService<ApiSettings>();
61+
var playerSettings = _host.Services.GetRequiredService<PlayerSettings>();
62+
var recordingSettings = _host.Services.GetRequiredService<RecordingSettings>();
63+
var epgSettings = _host.Services.GetRequiredService<EpgSettings>();
64+
var m3uSettings = _host.Services.GetRequiredService<M3uSettings>();
65+
var networkSettings = _host.Services.GetRequiredService<NetworkSettings>();
66+
67+
Session.InitializeConfiguration(apiSettings, playerSettings, recordingSettings, epgSettings, m3uSettings, networkSettings);
68+
69+
// Load settings
70+
SettingsStore.LoadIntoSession();
71+
72+
Log.Information("Configuration loaded successfully");
73+
74+
// Start with main window
75+
var mainWindow = _host.Services.GetRequiredService<MainWindow>();
76+
mainWindow.Show();
77+
78+
Log.Information("Main window displayed");
79+
80+
base.OnStartup(e);
81+
}
82+
catch (Exception ex)
83+
{
84+
Log.Fatal(ex, "Fatal error during application startup");
85+
MessageBox.Show(
86+
$"A fatal error occurred during startup:\n\n{ex.Message}\n\nPlease check the log file at:\n{GetLogDirectory()}",
87+
"Application Startup Error",
88+
MessageBoxButton.OK,
89+
MessageBoxImage.Error
90+
);
91+
Log.CloseAndFlush();
92+
Shutdown(1);
93+
}
94+
}
2395

24-
// Initialize Session with configuration settings
25-
var apiSettings = _host.Services.GetRequiredService<ApiSettings>();
26-
var playerSettings = _host.Services.GetRequiredService<PlayerSettings>();
27-
var recordingSettings = _host.Services.GetRequiredService<RecordingSettings>();
28-
var epgSettings = _host.Services.GetRequiredService<EpgSettings>();
29-
var m3uSettings = _host.Services.GetRequiredService<M3uSettings>();
30-
var networkSettings = _host.Services.GetRequiredService<NetworkSettings>();
96+
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
97+
{
98+
var exception = e.ExceptionObject as Exception;
99+
Log.Fatal(exception, "Unhandled exception in AppDomain");
100+
101+
if (e.IsTerminating)
102+
{
103+
MessageBox.Show(
104+
$"A fatal error occurred:\n\n{exception?.Message}\n\nThe application will now close.\n\nLog location: {GetLogDirectory()}",
105+
"Fatal Error",
106+
MessageBoxButton.OK,
107+
MessageBoxImage.Error
108+
);
109+
Log.CloseAndFlush();
110+
}
111+
}
112+
113+
private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
114+
{
115+
Log.Error(e.Exception, "Unhandled dispatcher exception");
31116

32-
Session.InitializeConfiguration(apiSettings, playerSettings, recordingSettings, epgSettings, m3uSettings, networkSettings);
117+
MessageBox.Show(
118+
$"An error occurred:\n\n{e.Exception.Message}\n\nLog location: {GetLogDirectory()}",
119+
"Error",
120+
MessageBoxButton.OK,
121+
MessageBoxImage.Error
122+
);
33123

34-
// Load settings
35-
SettingsStore.LoadIntoSession();
124+
// Mark as handled to prevent application crash
125+
e.Handled = true;
126+
}
36127

37-
// Start with main window
38-
var mainWindow = _host.Services.GetRequiredService<MainWindow>();
39-
mainWindow.Show();
128+
private void OnUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
129+
{
130+
Log.Error(e.Exception, "Unobserved task exception");
131+
e.SetObserved();
132+
}
40133

41-
base.OnStartup(e);
134+
private static string GetLogDirectory()
135+
{
136+
return Path.Combine(
137+
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
138+
"IPTV-Desktop-Browser",
139+
"Logs"
140+
);
42141
}
43142

44143
protected override void OnExit(ExitEventArgs e)
45144
{
46-
SettingsStore.SaveFromSession();
47-
_host?.Dispose();
145+
try
146+
{
147+
Log.Information("Application shutting down");
148+
SettingsStore.SaveFromSession();
149+
_host?.Dispose();
150+
}
151+
catch (Exception ex)
152+
{
153+
Log.Error(ex, "Error during application shutdown");
154+
}
155+
finally
156+
{
157+
Log.CloseAndFlush();
158+
}
159+
48160
base.OnExit(e);
49161
}
50162

@@ -53,12 +165,24 @@ private static IHostBuilder CreateHostBuilder()
53165
return Host.CreateDefaultBuilder()
54166
.ConfigureAppConfiguration((context, config) =>
55167
{
56-
// Get the base directory where the executable is located
57-
var basePath = AppDomain.CurrentDomain.BaseDirectory;
168+
// Get configuration path from AppData (auto-creates if missing)
169+
var configPath = Configuration.ConfigurationManager.GetConfigurationPath();
170+
var configDir = Path.GetDirectoryName(configPath) ?? AppDomain.CurrentDomain.BaseDirectory;
171+
172+
Log.Information("Loading configuration from: {ConfigPath}", configPath);
58173

59-
// Build configuration from appsettings.json
60-
config.SetBasePath(basePath)
61-
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
174+
// Build configuration from appsettings.json in AppData
175+
config.SetBasePath(configDir)
176+
.AddJsonFile(Path.GetFileName(configPath), optional: true, reloadOnChange: true);
177+
178+
if (File.Exists(configPath))
179+
{
180+
Log.Information("Configuration file loaded successfully from AppData");
181+
}
182+
else
183+
{
184+
Log.Warning("Configuration file not found, using default values");
185+
}
62186
})
63187
.ConfigureServices((context, services) =>
64188
{
@@ -105,17 +229,11 @@ private static IHostBuilder CreateHostBuilder()
105229
services.AddTransient<DashboardWindow>();
106230
services.AddTransient<CacheInspectorWindow>();
107231

108-
// Configure logging from configuration
232+
// Configure logging with Serilog
109233
services.AddLogging(builder =>
110234
{
111-
builder.AddConsole();
112-
builder.AddDebug();
113-
builder.SetMinimumLevel(LogLevel.Warning);
114-
// Reduce HTTP client logging noise
115-
builder.AddFilter("System.Net.Http", LogLevel.Warning);
116-
builder.AddFilter("Microsoft.Extensions.Http", LogLevel.Warning);
117-
// Reduce service logging noise
118-
builder.AddFilter("DesktopApp.Services", LogLevel.Warning);
235+
builder.ClearProviders();
236+
builder.AddSerilog(dispose: true);
119237
});
120238
});
121239
}

DesktopApp/Configuration/AppConfiguration.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@ public class AppConfiguration
1919
public class AppSettings
2020
{
2121
public string ApplicationName { get; set; } = "IPTV Desktop Browser";
22-
public string Version { get; set; } = "2.0.0";
22+
public string Version { get; set; } = GetDefaultVersion();
23+
24+
private static string GetDefaultVersion()
25+
{
26+
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
27+
var version = assembly.GetName().Version;
28+
return version != null ? $"{version.Major}.{version.Minor}.{version.Build}" : "2.1.0";
29+
}
2330
}
2431

2532
public class GitHubSettings
@@ -72,8 +79,16 @@ public class DefaultExtensions
7279
public class HttpSettings
7380
{
7481
public int DefaultTimeoutSeconds { get; set; } = 30;
75-
public string UserAgent { get; set; } = "IPTV-Desktop-Browser/2.0.0";
82+
public string UserAgent { get; set; } = GetDefaultUserAgent();
7683
public TimeoutSettings Timeouts { get; set; } = new();
84+
85+
private static string GetDefaultUserAgent()
86+
{
87+
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
88+
var version = assembly.GetName().Version;
89+
var versionString = version != null ? $"{version.Major}.{version.Minor}.{version.Build}" : "2.1.0";
90+
return $"IPTV-Desktop-Browser/{versionString}";
91+
}
7792
}
7893

7994
public class TimeoutSettings

0 commit comments

Comments
 (0)