add close button

This commit is contained in:
Vova
2024-05-05 16:19:58 +03:00
parent 3dfeea71f0
commit 12289c52f8
20 changed files with 327 additions and 191 deletions
+1
View File
@@ -1,5 +1,6 @@
namespace TV_Player.MAUI
{
[Serializable]
public class GroupInfo
{
public string Name { get; set; }
+124 -13
View File
@@ -1,14 +1,34 @@
using System.Net.Http.Headers;
using System.Text.RegularExpressions;
using System.Xml;
namespace TV_Player.MAUI
{
public class ProgramInfo : ObservableViewModelBase
{
private string _title;
private int _durationValue;
public string Title { get => _title; set => SetProperty(ref _title, value); }
public DateTime StartTime { get; set; }
public DateTime StopTime { get; set; }
public int DurationValue { get => _durationValue; set => SetProperty(ref _durationValue, value); }
}
public class ProgramGuide
{
public string Id { get; set; }
public string DisplayName { get; set; }
public List<ProgramInfo> Programs { get; set; } = new List<ProgramInfo>();
}
public static class M3UParser
{
public static async Task<List<M3UInfo>> DownloadM3UFromWebAsync(string url)
{
List<M3UInfo> playlistItems = new List<M3UInfo>();
public static async Task<List<ProgramGuide>> DownloadGuideFromWebAsync(string url)
{
List<ProgramGuide> epgChannels = new List<ProgramGuide>(); ;
using (var client = new HttpClient())
using (var request = new HttpRequestMessage())
{
@@ -18,14 +38,84 @@ namespace TV_Player.MAUI
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
// Parse M3U content
playlistItems = ParseM3UFromString(responseBody);
epgChannels = ParseEpg(responseBody);
}
return playlistItems;
return epgChannels;
}
static string[] SplitStringBeforeSeparator(string input, string separator)
private static List<ProgramGuide> ParseEpg(string epgData)
{
List<ProgramGuide> epgChannels = new List<ProgramGuide>();
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreWhitespace = true;
settings.IgnoreComments = true;
using (XmlReader reader = XmlReader.Create(new System.IO.StringReader(epgData), settings))
{
try
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "channel")
{
ProgramGuide channel = new ProgramGuide();
channel.Id = reader.GetAttribute("id");
reader.Read();
channel.DisplayName = reader.ReadElementContentAsString();
epgChannels.Add(channel);
continue;
}
if (reader.NodeType == XmlNodeType.Element && reader.Name == "programme")
{
ProgramInfo program = new ProgramInfo();
var id = reader.GetAttribute("channel");
var channel = epgChannels.FirstOrDefault(x => x.Id == id);
program.StartTime = DateTime.ParseExact(reader.GetAttribute("start"), "yyyyMMddHHmmss zzz", null);
program.StopTime = DateTime.ParseExact(reader.GetAttribute("stop"), "yyyyMMddHHmmss zzz", null);
reader.Read();
program.Title = reader.ReadElementContentAsString();
channel.Programs.Add(program);
}
else if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "channel")
{
break;
}
}
}
catch{}
}
return epgChannels;
}
private static async Task<string> ReadFile(string url)
{
string 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();
responseBody = await response.Content.ReadAsStringAsync();
}
return responseBody;
}
public static async Task<(List<M3UInfo> programList, string programGuide)> DownloadM3UFromWebAsync(string url)
{
var fileData=await ReadFile(url);
// Parse M3U content
return ParseM3UFromString(fileData);
}
private static string[] SplitStringBeforeSeparator(string input, string separator)
{
string[] parts = input.Split(separator);
@@ -43,10 +133,10 @@ namespace TV_Player.MAUI
return parts;
}
static List<M3UInfo> ParseM3UFromString(string content)
private static (List<M3UInfo> programList, string programGuide) ParseM3UFromString(string content)
{
List<M3UInfo> playlistItems = new List<M3UInfo>();
string programGuideLink = string.Empty;
try
{
var m3u = SplitStringBeforeSeparator(content, "#EXT");
@@ -60,6 +150,10 @@ namespace TV_Player.MAUI
playlistItems.Add(m3uInfo);
}
}
if (line.StartsWith("#EXTM3U"))
{
programGuideLink=ExtractXtvgUrl(line);
}
}
}
catch (Exception ex)
@@ -67,11 +161,10 @@ namespace TV_Player.MAUI
Console.WriteLine("Error reading M3U file: " + ex.Message);
}
return playlistItems;
return (playlistItems,programGuideLink);
}
static bool TryParseM3ULine(string m3uLine, out M3UInfo? info)
private static bool TryParseM3ULine(string m3uLine, out M3UInfo? info)
{
info = null;
string pattern = @"#EXTINF:\d+ CUID=""(?<CUID>.*?)"" number=""(?<Number>.*?)"" tvg-id=""(?<TvgID>.*?)"" tvg-name=""(?<TvgName>.*?)"".*?tvg-logo=""(?<Logo>.*?)"" group-title=""(?<GroupTitle>.*?)""[^,]*,(?<Name>.*)[^\r](?<URL>.*)$";
@@ -96,5 +189,23 @@ namespace TV_Player.MAUI
return false;
}
private static string ExtractXtvgUrl(string m3uEntry)
{
// Define a regular expression pattern to match x-tvg-url attribute
string pattern = @"x-tvg-url=""(.*?)""";
// Use Regex.Match to find the first match
Match match = Regex.Match(m3uEntry, pattern);
// Check if a match is found and get the value from the capturing group
if (match.Success && match.Groups.Count > 1)
{
return match.Groups[1].Value;
}
// Return null or an empty string if no match is found
return string.Empty;
}
}
}
+4 -1
View File
@@ -4,6 +4,7 @@ namespace TV_Player.MAUI
{
public class MainViewModel : ObservableViewModelBase
{
private IDisposable _groupsSubscriber;
private List<GroupInfo> _programs;
public List<GroupInfo> Programs
{
@@ -17,7 +18,7 @@ namespace TV_Player.MAUI
public MainViewModel()
{
ItemSelectedCommand = new Command(OnItemSelected);
ProgramsData.Instance.GroupsInformation.Subscribe(x=>Programs = x);
_groupsSubscriber = TVPlayerViewModel.Instance.PlaylistData.GroupsInformation.Subscribe(x => Programs = x);
}
private void OnItemSelected()
@@ -33,6 +34,8 @@ namespace TV_Player.MAUI
};
// Navigate to the OtherPage
navigation.PushAsync(programPage);
_groupsSubscriber.Dispose();
}
}
}
+3 -3
View File
@@ -1,5 +1,4 @@
using LibVLCSharp.Shared;
using System.Windows.Input;
using System.Windows.Input;
namespace TV_Player.MAUI
{
@@ -26,6 +25,7 @@ namespace TV_Player.MAUI
//_libVLC = new LibVLC();
//_mediaPlayer = new MediaPlayer(new Media(_libVLC, new Uri(_currentProgram.Url)));
//_mediaPlayer.Play();
URLSource = _currentProgram.Url;
PlayCommand = new Command(OnPlayButtonClicked);
}
@@ -40,7 +40,7 @@ namespace TV_Player.MAUI
{
URLSource = _currentProgram.Url;
}
catch (Exception ex)
catch
{
// Handle exceptions
}
+4 -1
View File
@@ -4,6 +4,7 @@ namespace TV_Player.MAUI
{
public class ProgramViewModel : ObservableViewModelBase
{
private IDisposable _programSubscriber;
private List<M3UInfo> _programs;
public List<M3UInfo> Programs
{
@@ -17,7 +18,7 @@ namespace TV_Player.MAUI
public ProgramViewModel(GroupInfo groupInfo)
{
ItemSelectedCommand = new Command(OnItemSelected);
ProgramsData.Instance.AllPrograms.Subscribe(x=>Programs = x.Where(p=>p.GroupTitle== groupInfo.Name).ToList());
_programSubscriber = TVPlayerViewModel.Instance.PlaylistData.AllPrograms.Subscribe(x => Programs = x.Where(p => p.GroupTitle == groupInfo.Name).ToList());
}
private void OnItemSelected()
@@ -33,6 +34,8 @@ namespace TV_Player.MAUI
};
// Navigate to the OtherPage
navigation.PushAsync(playerPage);
_programSubscriber.Dispose();
}
}
}
+25 -19
View File
@@ -4,36 +4,42 @@ namespace TV_Player.MAUI
{
public class ProgramsData
{
private static ProgramsData _instance;
public static ProgramsData Instance
{
get
{
_instance ??= new ProgramsData();
return _instance;
}
}
private readonly ReplaySubject<List<M3UInfo>> programsSubject = new ReplaySubject<List<M3UInfo>>();
private readonly ReplaySubject<List<GroupInfo>> groupsSubject = new ReplaySubject<List<GroupInfo>>();
private readonly ReplaySubject<List<ProgramGuide>> programGuideSubject = new ReplaySubject<List<ProgramGuide>>();
public IObservable<List<M3UInfo>> AllPrograms => programsSubject;
public IObservable<List<GroupInfo>> GroupsInformation => groupsSubject;
private ProgramsData()
{
_=Initialize();
public IObservable<List<ProgramGuide>> ProgramGuideInfo => programGuideSubject;
public ProgramsData()
{
}
private async Task Initialize()
private async Task GetPrograms(string m3uLink)
{
string m3uLink = "http://pl.da-tv.vip/a71e77fa/835b3216/tv.m3u";
var programs = await M3UParser.DownloadM3UFromWebAsync(m3uLink);
//string m3uLink = "http://pl.da-tv.vip/a71e77fa/835b3216/tv.m3u";
var result = await M3UParser.DownloadM3UFromWebAsync(m3uLink);
programsSubject.OnNext(result.programList);
programsSubject.OnNext(programs);
var groupping = programs.GroupBy(item => item.GroupTitle)
var groupping = result.programList.GroupBy(item => item.GroupTitle)
.Select(group => new GroupInfo() { Name = group.Key, Count = group.Count() })
.ToList();
groupsSubject.OnNext(groupping);
await Task.Run(() => GetProgramGuide(result.programGuide));
}
private async Task GetProgramGuide(string guideLink)
{
//string guideLink = "http://epg.da-tv.vip/107-light.xml";
var programGuide = await M3UParser.DownloadGuideFromWebAsync(guideLink);
programGuideSubject.OnNext(programGuide);
}
internal void GetData(string playlistURL)
{
Task.Run(() => GetPrograms(playlistURL));
}
}
}
+28
View File
@@ -0,0 +1,28 @@
namespace TV_Player.MAUI
{
public class TVPlayerViewModel
{
public ProgramsData PlaylistData { get; private set; }
public Action ButtonBackAction { get; set; }
private static TVPlayerViewModel _instance;
public static TVPlayerViewModel Instance
{
get
{
if (_instance == null)
_instance = new TVPlayerViewModel();
return _instance;
}
}
public TVPlayerViewModel()
{
PlaylistData = new ProgramsData();
PlaylistData.GetData("http://pl.da-tv.vip/a71e77fa/835b3216/tv.m3u");
}
}
}