Enhance error handling and logging in M3U and XML downloading processes; implement proper application shutdown in MainViewModel; introduce PlaylistSettings for configurable URLs and timeout settings.

This commit is contained in:
Vladimir
2026-03-22 09:14:39 +02:00
parent 59d0ed1ab5
commit a6ec011e79
9 changed files with 270 additions and 181 deletions
+87 -31
View File
@@ -66,16 +66,28 @@ namespace TV_Player
private static async Task<string> DownloadXMLProgram(string url)
{
using (var client = new HttpClient())
using (var request = new HttpRequestMessage())
try
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/text"));
request.Method = HttpMethod.Get;
request.RequestUri = new Uri(url);
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
return responseBody;
using (var client = new HttpClient())
using (var request = new HttpRequestMessage())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/text"));
request.Method = HttpMethod.Get;
request.RequestUri = new Uri(url);
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
catch (HttpRequestException ex)
{
System.Diagnostics.Debug.WriteLine($"Network error downloading XML from {url}: {ex.Message}");
throw;
}
catch (UriFormatException ex)
{
System.Diagnostics.Debug.WriteLine($"Invalid URL: {url} - {ex.Message}");
throw;
}
}
@@ -91,15 +103,22 @@ namespace TV_Player
using MemoryStream decompressedStream = new MemoryStream();
await decompressionStream.CopyToAsync(decompressedStream);
// Step 3: Get the inner XML as a string
string xmlContent = Encoding.UTF8.GetString(decompressedStream.ToArray());
// Output the XML content
return xmlContent;
}
catch (HttpRequestException ex)
{
System.Diagnostics.Debug.WriteLine($"Network error downloading gzip from {url}: {ex.Message}");
return null;
}
catch (InvalidOperationException ex)
{
System.Diagnostics.Debug.WriteLine($"Invalid gzip data: {ex.Message}");
return null;
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
System.Diagnostics.Debug.WriteLine($"Error decompressing gzip: {ex.Message}");
return null;
}
}
@@ -117,6 +136,12 @@ namespace TV_Player
string programDataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
string filePath = Path.Combine(programDataPath, "TVPlayer", fileName);
if (!File.Exists(filePath))
{
System.Diagnostics.Debug.WriteLine($"EPG file not found: {filePath}");
return null;
}
using (XmlReader reader = XmlReader.Create(filePath, settings))
{
try
@@ -134,7 +159,6 @@ namespace TV_Player
};
reader.Read();
channel.DisplayName = reader.ReadElementContentAsString();
}
continue;
}
@@ -145,22 +169,33 @@ namespace TV_Player
var id = reader.GetAttribute("channel");
if (id != channelId) continue;
program.StartTime = DateTime.ParseExact(reader.GetAttribute("start"), "yyyyMMddHHmmss zzz", null);
program.EndTime = DateTime.ParseExact(reader.GetAttribute("stop"), "yyyyMMddHHmmss zzz", null);
if (!DateTime.TryParseExact(reader.GetAttribute("start"), "yyyyMMddHHmmss zzz", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out var startTime))
continue;
if (!DateTime.TryParseExact(reader.GetAttribute("stop"), "yyyyMMddHHmmss zzz", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out var endTime))
continue;
program.StartTime = startTime;
program.EndTime = endTime;
reader.Read();
program.Title = reader.ReadElementContentAsString();
channel.Programs.Add(program);
}
else if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "channel")
{
// break;
}
}
}
catch (XmlException ex)
{
System.Diagnostics.Debug.WriteLine($"XML parsing error in EPG file: {ex.Message}");
}
catch (FileNotFoundException ex)
{
System.Diagnostics.Debug.WriteLine($"EPG file not found: {ex.Message}");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Unexpected error parsing EPG: {ex.Message}");
}
}
return channel;
@@ -168,18 +203,29 @@ namespace TV_Player
private static async Task<string> ReadFile(string url)
{
string responseBody;
using (var client = new HttpClient())
using (var request = new HttpRequestMessage())
try
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/text"));
request.Method = HttpMethod.Get;
request.RequestUri = new Uri(url);
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
responseBody = await response.Content.ReadAsStringAsync();
using (var client = new HttpClient())
using (var request = new HttpRequestMessage())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/text"));
request.Method = HttpMethod.Get;
request.RequestUri = new Uri(url);
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
catch (HttpRequestException ex)
{
System.Diagnostics.Debug.WriteLine($"Network error reading file from {url}: {ex.Message}");
throw;
}
catch (UriFormatException ex)
{
System.Diagnostics.Debug.WriteLine($"Invalid URL: {url} - {ex.Message}");
throw;
}
return responseBody;
}
public static async Task<(List<M3UInfo> programList, string programGuide)> DownloadM3UFromWebAsync(string url)
@@ -220,6 +266,12 @@ namespace TV_Player
string programGuideLink = string.Empty;
try
{
if (string.IsNullOrWhiteSpace(content))
{
System.Diagnostics.Debug.WriteLine("M3U content is empty");
return (playlistItems, programGuideLink);
}
var m3u = SplitStringBeforeSeparator(content, "#EXT");
foreach (var line in m3u)
@@ -238,9 +290,13 @@ namespace TV_Player
}
}
}
catch (ArgumentException ex)
{
System.Diagnostics.Debug.WriteLine($"Invalid M3U format: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine("Error reading M3U file: " + ex.Message);
System.Diagnostics.Debug.WriteLine($"Error parsing M3U file: {ex.Message}");
}
return (playlistItems, programGuideLink);
+8 -1
View File
@@ -69,7 +69,14 @@ namespace TV_Player
public void OnCloseAppButtonClick()
{
Environment.Exit(0);
if (Application.Current?.MainWindow is Window window)
{
window.Close(); // Allows proper shutdown sequence
}
else
{
Environment.Exit(0); // Fallback if window not available
}
}
private void OnButtonBackClick()