diff --git a/TV Player/App.xaml b/TV Player/App.xaml
new file mode 100644
index 0000000..afed686
--- /dev/null
+++ b/TV Player/App.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TV Player/App.xaml.cs b/TV Player/App.xaml.cs
new file mode 100644
index 0000000..8a99059
--- /dev/null
+++ b/TV Player/App.xaml.cs
@@ -0,0 +1,12 @@
+namespace TV_Player
+{
+ public partial class App : Application
+ {
+ public App()
+ {
+ InitializeComponent();
+
+ MainPage = new AppShell();
+ }
+ }
+}
diff --git a/TV Player/AppShell.xaml b/TV Player/AppShell.xaml
new file mode 100644
index 0000000..d5d383b
--- /dev/null
+++ b/TV Player/AppShell.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/TV Player/AppShell.xaml.cs b/TV Player/AppShell.xaml.cs
new file mode 100644
index 0000000..ed0c74f
--- /dev/null
+++ b/TV Player/AppShell.xaml.cs
@@ -0,0 +1,10 @@
+namespace TV_Player
+{
+ public partial class AppShell : Shell
+ {
+ public AppShell()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/TV Player/MainPage.xaml b/TV Player/MainPage.xaml
new file mode 100644
index 0000000..4e3ce52
--- /dev/null
+++ b/TV Player/MainPage.xaml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TV Player/MainPage.xaml.cs b/TV Player/MainPage.xaml.cs
new file mode 100644
index 0000000..352c26a
--- /dev/null
+++ b/TV Player/MainPage.xaml.cs
@@ -0,0 +1,23 @@
+namespace TV_Player
+{
+ public partial class MainPage : ContentPage
+ {
+ public MainPage()
+ {
+ InitializeComponent();
+ }
+
+ //private void OnCounterClicked(object sender, EventArgs e)
+ //{
+ // count++;
+
+ // if (count == 1)
+ // CounterBtn.Text = $"Clicked {count} time";
+ // else
+ // CounterBtn.Text = $"Clicked {count} times";
+
+ // SemanticScreenReader.Announce(CounterBtn.Text);
+ //}
+ }
+
+}
diff --git a/TV Player/MauiProgram.cs b/TV Player/MauiProgram.cs
new file mode 100644
index 0000000..df475a4
--- /dev/null
+++ b/TV Player/MauiProgram.cs
@@ -0,0 +1,25 @@
+using Microsoft.Extensions.Logging;
+
+namespace TV_Player
+{
+ public static class MauiProgram
+ {
+ public static MauiApp CreateMauiApp()
+ {
+ var builder = MauiApp.CreateBuilder();
+ builder
+ .UseMauiApp()
+ .ConfigureFonts(fonts =>
+ {
+ fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
+ fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
+ });
+
+#if DEBUG
+ builder.Logging.AddDebug();
+#endif
+
+ return builder.Build();
+ }
+ }
+}
diff --git a/TV Player/Platforms/Android/AndroidManifest.xml b/TV Player/Platforms/Android/AndroidManifest.xml
new file mode 100644
index 0000000..e9937ad
--- /dev/null
+++ b/TV Player/Platforms/Android/AndroidManifest.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TV Player/Platforms/Android/MainActivity.cs b/TV Player/Platforms/Android/MainActivity.cs
new file mode 100644
index 0000000..5296c3d
--- /dev/null
+++ b/TV Player/Platforms/Android/MainActivity.cs
@@ -0,0 +1,11 @@
+using Android.App;
+using Android.Content.PM;
+using Android.OS;
+
+namespace TV_Player
+{
+ [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
+ public class MainActivity : MauiAppCompatActivity
+ {
+ }
+}
diff --git a/TV Player/Platforms/Android/MainApplication.cs b/TV Player/Platforms/Android/MainApplication.cs
new file mode 100644
index 0000000..8424df7
--- /dev/null
+++ b/TV Player/Platforms/Android/MainApplication.cs
@@ -0,0 +1,16 @@
+using Android.App;
+using Android.Runtime;
+
+namespace TV_Player
+{
+ [Application]
+ public class MainApplication : MauiApplication
+ {
+ public MainApplication(IntPtr handle, JniHandleOwnership ownership)
+ : base(handle, ownership)
+ {
+ }
+
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+ }
+}
diff --git a/TV Player/Platforms/Android/Resources/values/colors.xml b/TV Player/Platforms/Android/Resources/values/colors.xml
new file mode 100644
index 0000000..c04d749
--- /dev/null
+++ b/TV Player/Platforms/Android/Resources/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #512BD4
+ #2B0B98
+ #2B0B98
+
\ No newline at end of file
diff --git a/TV Player/Platforms/MacCatalyst/AppDelegate.cs b/TV Player/Platforms/MacCatalyst/AppDelegate.cs
new file mode 100644
index 0000000..237a786
--- /dev/null
+++ b/TV Player/Platforms/MacCatalyst/AppDelegate.cs
@@ -0,0 +1,10 @@
+using Foundation;
+
+namespace TV_Player
+{
+ [Register("AppDelegate")]
+ public class AppDelegate : MauiUIApplicationDelegate
+ {
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+ }
+}
diff --git a/TV Player/Platforms/MacCatalyst/Info.plist b/TV Player/Platforms/MacCatalyst/Info.plist
new file mode 100644
index 0000000..c96dd0a
--- /dev/null
+++ b/TV Player/Platforms/MacCatalyst/Info.plist
@@ -0,0 +1,30 @@
+
+
+
+
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ XSAppIconAssets
+ Assets.xcassets/appicon.appiconset
+
+
diff --git a/TV Player/Platforms/MacCatalyst/Program.cs b/TV Player/Platforms/MacCatalyst/Program.cs
new file mode 100644
index 0000000..d6861d1
--- /dev/null
+++ b/TV Player/Platforms/MacCatalyst/Program.cs
@@ -0,0 +1,16 @@
+using ObjCRuntime;
+using UIKit;
+
+namespace TV_Player
+{
+ public class Program
+ {
+ // This is the main entry point of the application.
+ static void Main(string[] args)
+ {
+ // if you want to use a different Application Delegate class from "AppDelegate"
+ // you can specify it here.
+ UIApplication.Main(args, null, typeof(AppDelegate));
+ }
+ }
+}
diff --git a/TV Player/Platforms/Tizen/Main.cs b/TV Player/Platforms/Tizen/Main.cs
new file mode 100644
index 0000000..2c6aa6e
--- /dev/null
+++ b/TV Player/Platforms/Tizen/Main.cs
@@ -0,0 +1,17 @@
+using Microsoft.Maui;
+using Microsoft.Maui.Hosting;
+using System;
+
+namespace TV_Player
+{
+ internal class Program : MauiApplication
+ {
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+
+ static void Main(string[] args)
+ {
+ var app = new Program();
+ app.Run(args);
+ }
+ }
+}
diff --git a/TV Player/Platforms/Tizen/tizen-manifest.xml b/TV Player/Platforms/Tizen/tizen-manifest.xml
new file mode 100644
index 0000000..f3f0641
--- /dev/null
+++ b/TV Player/Platforms/Tizen/tizen-manifest.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ maui-appicon-placeholder
+
+
+
+
+ http://tizen.org/privilege/internet
+
+
+
+
\ No newline at end of file
diff --git a/TV Player/Platforms/Windows/App.xaml b/TV Player/Platforms/Windows/App.xaml
new file mode 100644
index 0000000..41a5378
--- /dev/null
+++ b/TV Player/Platforms/Windows/App.xaml
@@ -0,0 +1,8 @@
+
+
+
diff --git a/TV Player/Platforms/Windows/App.xaml.cs b/TV Player/Platforms/Windows/App.xaml.cs
new file mode 100644
index 0000000..98341ae
--- /dev/null
+++ b/TV Player/Platforms/Windows/App.xaml.cs
@@ -0,0 +1,25 @@
+using Microsoft.UI.Xaml;
+
+// To learn more about WinUI, the WinUI project structure,
+// and more about our project templates, see: http://aka.ms/winui-project-info.
+
+namespace TV_Player.WinUI
+{
+ ///
+ /// Provides application-specific behavior to supplement the default Application class.
+ ///
+ public partial class App : MauiWinUIApplication
+ {
+ ///
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ ///
+ public App()
+ {
+ this.InitializeComponent();
+ }
+
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+ }
+
+}
diff --git a/TV Player/Platforms/Windows/Package.appxmanifest b/TV Player/Platforms/Windows/Package.appxmanifest
new file mode 100644
index 0000000..4211f56
--- /dev/null
+++ b/TV Player/Platforms/Windows/Package.appxmanifest
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+ $placeholder$
+ User Name
+ $placeholder$.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TV Player/Platforms/Windows/app.manifest b/TV Player/Platforms/Windows/app.manifest
new file mode 100644
index 0000000..211915d
--- /dev/null
+++ b/TV Player/Platforms/Windows/app.manifest
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+ true/PM
+ PerMonitorV2, PerMonitor
+
+
+
diff --git a/TV Player/Platforms/iOS/AppDelegate.cs b/TV Player/Platforms/iOS/AppDelegate.cs
new file mode 100644
index 0000000..237a786
--- /dev/null
+++ b/TV Player/Platforms/iOS/AppDelegate.cs
@@ -0,0 +1,10 @@
+using Foundation;
+
+namespace TV_Player
+{
+ [Register("AppDelegate")]
+ public class AppDelegate : MauiUIApplicationDelegate
+ {
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+ }
+}
diff --git a/TV Player/Platforms/iOS/Info.plist b/TV Player/Platforms/iOS/Info.plist
new file mode 100644
index 0000000..0004a4f
--- /dev/null
+++ b/TV Player/Platforms/iOS/Info.plist
@@ -0,0 +1,32 @@
+
+
+
+
+ LSRequiresIPhoneOS
+
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ XSAppIconAssets
+ Assets.xcassets/appicon.appiconset
+
+
diff --git a/TV Player/Platforms/iOS/Program.cs b/TV Player/Platforms/iOS/Program.cs
new file mode 100644
index 0000000..d6861d1
--- /dev/null
+++ b/TV Player/Platforms/iOS/Program.cs
@@ -0,0 +1,16 @@
+using ObjCRuntime;
+using UIKit;
+
+namespace TV_Player
+{
+ public class Program
+ {
+ // This is the main entry point of the application.
+ static void Main(string[] args)
+ {
+ // if you want to use a different Application Delegate class from "AppDelegate"
+ // you can specify it here.
+ UIApplication.Main(args, null, typeof(AppDelegate));
+ }
+ }
+}
diff --git a/TV Player/Properties/launchSettings.json b/TV Player/Properties/launchSettings.json
new file mode 100644
index 0000000..edf8aad
--- /dev/null
+++ b/TV Player/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "Windows Machine": {
+ "commandName": "MsixPackage",
+ "nativeDebugging": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/TV Player/Resources/AppIcon/appicon.svg b/TV Player/Resources/AppIcon/appicon.svg
new file mode 100644
index 0000000..9d63b65
--- /dev/null
+++ b/TV Player/Resources/AppIcon/appicon.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/TV Player/Resources/AppIcon/appiconfg.svg b/TV Player/Resources/AppIcon/appiconfg.svg
new file mode 100644
index 0000000..21dfb25
--- /dev/null
+++ b/TV Player/Resources/AppIcon/appiconfg.svg
@@ -0,0 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/TV Player/Resources/Fonts/OpenSans-Regular.ttf b/TV Player/Resources/Fonts/OpenSans-Regular.ttf
new file mode 100644
index 0000000..dadcb01
Binary files /dev/null and b/TV Player/Resources/Fonts/OpenSans-Regular.ttf differ
diff --git a/TV Player/Resources/Fonts/OpenSans-Semibold.ttf b/TV Player/Resources/Fonts/OpenSans-Semibold.ttf
new file mode 100644
index 0000000..5601642
Binary files /dev/null and b/TV Player/Resources/Fonts/OpenSans-Semibold.ttf differ
diff --git a/TV Player/Resources/Images/dotnet_bot.svg b/TV Player/Resources/Images/dotnet_bot.svg
new file mode 100644
index 0000000..abfaff2
--- /dev/null
+++ b/TV Player/Resources/Images/dotnet_bot.svg
@@ -0,0 +1,93 @@
+
diff --git a/TV Player/Resources/Raw/AboutAssets.txt b/TV Player/Resources/Raw/AboutAssets.txt
new file mode 100644
index 0000000..15d6244
--- /dev/null
+++ b/TV Player/Resources/Raw/AboutAssets.txt
@@ -0,0 +1,15 @@
+Any raw assets you want to be deployed with your application can be placed in
+this directory (and child directories). Deployment of the asset to your application
+is automatically handled by the following `MauiAsset` Build Action within your `.csproj`.
+
+
+
+These files will be deployed with you package and will be accessible using Essentials:
+
+ async Task LoadMauiAsset()
+ {
+ using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt");
+ using var reader = new StreamReader(stream);
+
+ var contents = reader.ReadToEnd();
+ }
diff --git a/TV Player/Resources/Splash/splash.svg b/TV Player/Resources/Splash/splash.svg
new file mode 100644
index 0000000..21dfb25
--- /dev/null
+++ b/TV Player/Resources/Splash/splash.svg
@@ -0,0 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/TV Player/Resources/Styles/Colors.xaml b/TV Player/Resources/Styles/Colors.xaml
new file mode 100644
index 0000000..245758b
--- /dev/null
+++ b/TV Player/Resources/Styles/Colors.xaml
@@ -0,0 +1,44 @@
+
+
+
+
+ #512BD4
+ #DFD8F7
+ #2B0B98
+ White
+ Black
+ #E1E1E1
+ #C8C8C8
+ #ACACAC
+ #919191
+ #6E6E6E
+ #404040
+ #212121
+ #141414
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #F7B548
+ #FFD590
+ #FFE5B9
+ #28C2D1
+ #7BDDEF
+ #C3F2F4
+ #3E8EED
+ #72ACF1
+ #A7CBF6
+
+
\ No newline at end of file
diff --git a/TV Player/Resources/Styles/Styles.xaml b/TV Player/Resources/Styles/Styles.xaml
new file mode 100644
index 0000000..dc4a034
--- /dev/null
+++ b/TV Player/Resources/Styles/Styles.xaml
@@ -0,0 +1,405 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TV Player/TV Player.csproj b/TV Player/TV Player.csproj
new file mode 100644
index 0000000..d298b45
--- /dev/null
+++ b/TV Player/TV Player.csproj
@@ -0,0 +1,68 @@
+
+
+
+ net8.0-android
+ $(TargetFrameworks);net8.0-windows10.0.19041.0
+
+
+ Exe
+ TV_Player
+ true
+ true
+ enable
+
+
+ TV Player
+
+
+ com.companyname.tv_player
+ 5d5f328c-695f-403a-b602-eb8e64927cc2
+
+
+ 1.0
+ 1
+
+ 11.0
+ 13.1
+ 21.0
+ 10.0.17763.0
+ 10.0.17763.0
+ 6.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 7.0.1
+
+
+
+
+
+ 7.0.1
+
+
+
+
diff --git a/TV Player/ViewModels/GroupInfo.cs b/TV Player/ViewModels/GroupInfo.cs
new file mode 100644
index 0000000..99a3d84
--- /dev/null
+++ b/TV Player/ViewModels/GroupInfo.cs
@@ -0,0 +1,9 @@
+namespace TV_Player
+{
+ public class GroupInfo
+
+ {
+ public string Name { get; set; }
+ public int Count { get; set; }
+ }
+}
diff --git a/TV Player/ViewModels/M3UInfo.cs b/TV Player/ViewModels/M3UInfo.cs
new file mode 100644
index 0000000..c46ee17
--- /dev/null
+++ b/TV Player/ViewModels/M3UInfo.cs
@@ -0,0 +1,14 @@
+namespace TV_Player
+{
+ public class M3UInfo
+ {
+ public string CUID { get; set; }
+ public string Number { get; set; }
+ public string TvgID { get; set; }
+ public string TvgName { get; set; }
+ public string GroupTitle { get; set; }
+ public string Logo { get; set; }
+ public string Name{ get; set; }
+ public string Url { get; set; }
+ }
+}
diff --git a/TV Player/ViewModels/M3UParser.cs b/TV Player/ViewModels/M3UParser.cs
new file mode 100644
index 0000000..9143db0
--- /dev/null
+++ b/TV Player/ViewModels/M3UParser.cs
@@ -0,0 +1,100 @@
+using System.Net.Http.Headers;
+using System.Text.RegularExpressions;
+
+namespace TV_Player
+{
+ public static class M3UParser
+ {
+ public static async Task> DownloadM3UFromWebAsync(string url)
+ {
+ List playlistItems = new List();
+
+ 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();
+ string responseBody = await response.Content.ReadAsStringAsync();
+
+ // Parse M3U content
+ playlistItems = ParseM3UFromString(responseBody);
+ }
+ return playlistItems;
+ }
+
+ static string[] SplitStringBeforeSeparator(string input, string separator)
+ {
+ string[] parts = input.Split(separator);
+
+ // Reconstruct the string until the separator is reached
+ int separatorIndex = input.IndexOf(separator);
+ if (separatorIndex != -1)
+ {
+ parts[0] = input.Substring(0, separatorIndex + 1);
+ for (int i = 1; i < parts.Length; i++)
+ {
+ parts[i] = separator + parts[i];
+ }
+ }
+
+ return parts;
+ }
+
+ static List ParseM3UFromString(string content)
+ {
+ List playlistItems = new List();
+
+ try
+ {
+ var m3u = SplitStringBeforeSeparator(content, "#EXT");
+
+ foreach (var line in m3u)
+ {
+ if (line.StartsWith("#EXTINF:"))
+ {
+ if (TryParseM3ULine(line, out var m3uInfo))
+ {
+ playlistItems.Add(m3uInfo);
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("Error reading M3U file: " + ex.Message);
+ }
+
+ return playlistItems;
+ }
+
+
+ static bool TryParseM3ULine(string m3uLine, out M3UInfo? info)
+ {
+ info = null;
+ string pattern = @"#EXTINF:\d+ CUID=""(?.*?)"" number=""(?.*?)"" tvg-id=""(?.*?)"" tvg-name=""(?.*?)"".*?tvg-logo=""(?.*?)"" group-title=""(?.*?)""[^,]*,(?.*)[^\r](?.*)$";
+ Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
+
+ Match match = regex.Match(m3uLine);
+ if (match.Success)
+ {
+ info = new M3UInfo
+ {
+ CUID = match.Groups["CUID"].Value,
+ Number = match.Groups["Number"].Value,
+ TvgID = match.Groups["TvgID"].Value,
+ TvgName = match.Groups["TvgName"].Value,
+ GroupTitle = match.Groups["GroupTitle"].Value,
+ Logo = match.Groups["Logo"].Value,
+ Name = match.Groups["Name"].Value,
+ Url = match.Groups["Url"].Value
+ };
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/TV Player/ViewModels/MainViewModel.cs b/TV Player/ViewModels/MainViewModel.cs
new file mode 100644
index 0000000..7ff8653
--- /dev/null
+++ b/TV Player/ViewModels/MainViewModel.cs
@@ -0,0 +1,28 @@
+using System.Windows.Input;
+
+namespace TV_Player
+{
+ public class MainViewModel : ObservableViewModelBase
+ {
+ private List _programs;
+ public List Programs
+ {
+ get => _programs;
+ set => SetProperty(ref _programs, value);
+ }
+
+ public GroupInfo SelectedItem { get; set; }
+ public ICommand ItemSelectedCommand { get; }
+
+ public MainViewModel()
+ {
+ ItemSelectedCommand = new Command(OnItemSelected);
+ ProgramsData.Instance.GroupsInformation.Subscribe(x=>Programs = x);
+ }
+
+ private void OnItemSelected()
+ {
+
+ }
+ }
+}
diff --git a/TV Player/ViewModels/ObservableViewModelBase.cs b/TV Player/ViewModels/ObservableViewModelBase.cs
new file mode 100644
index 0000000..f54f263
--- /dev/null
+++ b/TV Player/ViewModels/ObservableViewModelBase.cs
@@ -0,0 +1,28 @@
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+
+namespace TV_Player
+{
+ public abstract class ObservableViewModelBase : INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ protected void RaisePropertyChanged(string propertyName)
+ => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+
+ ///
+ /// Set a property and raise a property changed event if it has changed
+ ///
+ protected bool SetProperty(ref T property, T value, [CallerMemberName] string propertyName = null)
+ {
+ if (EqualityComparer.Default.Equals(property, value))
+ {
+ return false;
+ }
+
+ property = value;
+ RaisePropertyChanged(propertyName);
+ return true;
+ }
+ }
+}
diff --git a/TV Player/ViewModels/ProgramsData.cs b/TV Player/ViewModels/ProgramsData.cs
new file mode 100644
index 0000000..0d5e8e6
--- /dev/null
+++ b/TV Player/ViewModels/ProgramsData.cs
@@ -0,0 +1,39 @@
+using System.Reactive.Subjects;
+
+namespace TV_Player
+{
+ public class ProgramsData
+ {
+ private static ProgramsData _instance;
+ public static ProgramsData Instance
+ {
+ get
+ {
+ _instance ??= new ProgramsData();
+ return _instance;
+ }
+ }
+
+ private readonly Subject> programsSubject = new Subject>();
+ private readonly Subject> groupsSubject = new Subject>();
+ public IObservable> AllPrograms => programsSubject;
+ public Subject> GroupsInformation => groupsSubject;
+
+ private ProgramsData()
+ {
+ _=Initialize();
+ }
+ private async Task Initialize()
+ {
+ string m3uLink = "http://pl.da-tv.vip/a71e77fa/835b3216/tv.m3u";
+ var programs = await M3UParser.DownloadM3UFromWebAsync(m3uLink);
+
+ programsSubject.OnNext(programs);
+
+ var groupping = programs.GroupBy(item => item.GroupTitle)
+ .Select(group => new GroupInfo() { Name = group.Key, Count = group.Count() })
+ .ToList();
+ groupsSubject.OnNext(groupping);
+ }
+ }
+}
diff --git a/TV Player_old/App.xaml b/TV Player_old/App.xaml
new file mode 100644
index 0000000..1dee3fc
--- /dev/null
+++ b/TV Player_old/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/TV Player_old/App.xaml.cs b/TV Player_old/App.xaml.cs
new file mode 100644
index 0000000..ac39428
--- /dev/null
+++ b/TV Player_old/App.xaml.cs
@@ -0,0 +1,14 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace TV_Player
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ }
+
+}
diff --git a/TV Player_old/AssemblyInfo.cs b/TV Player_old/AssemblyInfo.cs
new file mode 100644
index 0000000..b0ec827
--- /dev/null
+++ b/TV Player_old/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/TV Player_old/Assets/bkground.jpg b/TV Player_old/Assets/bkground.jpg
new file mode 100644
index 0000000..73f1a2d
Binary files /dev/null and b/TV Player_old/Assets/bkground.jpg differ
diff --git a/TV Player_old/EnumToBooleanConverter.cs b/TV Player_old/EnumToBooleanConverter.cs
new file mode 100644
index 0000000..1205a56
--- /dev/null
+++ b/TV Player_old/EnumToBooleanConverter.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+
+namespace TV_Player
+{
+ public class EnumToBooleanConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return value.Equals(parameter);
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return value.Equals(true) ? parameter : Binding.DoNothing;
+ }
+ }
+}
diff --git a/TV Player_old/GroupButton.xaml b/TV Player_old/GroupButton.xaml
new file mode 100644
index 0000000..7f54c71
--- /dev/null
+++ b/TV Player_old/GroupButton.xaml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Programs
+
+
+
+
+
diff --git a/TV Player_old/GroupButton.xaml.cs b/TV Player_old/GroupButton.xaml.cs
new file mode 100644
index 0000000..d9985fb
--- /dev/null
+++ b/TV Player_old/GroupButton.xaml.cs
@@ -0,0 +1,17 @@
+using System.Windows.Controls;
+
+namespace TV_Player
+{
+ ///
+ /// Interaction logic for GroupButton.xaml
+ ///
+ public partial class GroupButton : UserControl
+ {
+ public GroupButton(string groupName,int programsFound)
+ {
+ InitializeComponent();
+ this.groupName.Text = groupName;
+ this.programsFound.Text = programsFound.ToString();
+ }
+ }
+}
diff --git a/TV Player_old/M3UInfo.cs b/TV Player_old/M3UInfo.cs
new file mode 100644
index 0000000..c46ee17
--- /dev/null
+++ b/TV Player_old/M3UInfo.cs
@@ -0,0 +1,14 @@
+namespace TV_Player
+{
+ public class M3UInfo
+ {
+ public string CUID { get; set; }
+ public string Number { get; set; }
+ public string TvgID { get; set; }
+ public string TvgName { get; set; }
+ public string GroupTitle { get; set; }
+ public string Logo { get; set; }
+ public string Name{ get; set; }
+ public string Url { get; set; }
+ }
+}
diff --git a/TV Player_old/M3UParser.cs b/TV Player_old/M3UParser.cs
new file mode 100644
index 0000000..765c6e9
--- /dev/null
+++ b/TV Player_old/M3UParser.cs
@@ -0,0 +1,101 @@
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Text.RegularExpressions;
+
+namespace TV_Player
+{
+ public static class M3UParser
+ {
+ public static async Task> DownloadM3UFromWebAsync(string url)
+ {
+ List playlistItems = new List();
+
+ 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();
+ string responseBody = await response.Content.ReadAsStringAsync();
+
+ // Parse M3U content
+ playlistItems = ParseM3UFromString(responseBody);
+ }
+ return playlistItems;
+ }
+
+ static string[] SplitStringBeforeSeparator(string input, string separator)
+ {
+ string[] parts = input.Split(separator);
+
+ // Reconstruct the string until the separator is reached
+ int separatorIndex = input.IndexOf(separator);
+ if (separatorIndex != -1)
+ {
+ parts[0] = input.Substring(0, separatorIndex + 1);
+ for (int i = 1; i < parts.Length; i++)
+ {
+ parts[i] = separator + parts[i];
+ }
+ }
+
+ return parts;
+ }
+
+ static List ParseM3UFromString(string content)
+ {
+ List playlistItems = new List();
+
+ try
+ {
+ var m3u = SplitStringBeforeSeparator(content, "#EXT");
+
+ foreach (var line in m3u)
+ {
+ if (line.StartsWith("#EXTINF:"))
+ {
+ if (TryParseM3ULine(line, out var m3uInfo))
+ {
+ playlistItems.Add(m3uInfo);
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("Error reading M3U file: " + ex.Message);
+ }
+
+ return playlistItems;
+ }
+
+
+ static bool TryParseM3ULine(string m3uLine, out M3UInfo? info)
+ {
+ info = null;
+ string pattern = @"#EXTINF:\d+ CUID=""(?.*?)"" number=""(?.*?)"" tvg-id=""(?.*?)"" tvg-name=""(?.*?)"".*?tvg-logo=""(?.*?)"" group-title=""(?.*?)""[^,]*,(?.*)[^\r](?.*)$";
+ Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
+
+ Match match = regex.Match(m3uLine);
+ if (match.Success)
+ {
+ info = new M3UInfo
+ {
+ CUID = match.Groups["CUID"].Value,
+ Number = match.Groups["Number"].Value,
+ TvgID = match.Groups["TvgID"].Value,
+ TvgName = match.Groups["TvgName"].Value,
+ GroupTitle = match.Groups["GroupTitle"].Value,
+ Logo = match.Groups["Logo"].Value,
+ Name = match.Groups["Name"].Value,
+ Url = match.Groups["Url"].Value
+ };
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/TV Player_old/MainWindow.xaml b/TV Player_old/MainWindow.xaml
new file mode 100644
index 0000000..edfd22e
--- /dev/null
+++ b/TV Player_old/MainWindow.xaml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TV Player_old/MainWindow.xaml.cs b/TV Player_old/MainWindow.xaml.cs
new file mode 100644
index 0000000..23fedba
--- /dev/null
+++ b/TV Player_old/MainWindow.xaml.cs
@@ -0,0 +1,102 @@
+using System.ComponentModel;
+using System.Data.Common;
+using System.IO;
+using System.Reflection;
+using System.Windows;
+using System.Windows.Controls;
+using Vlc.DotNet.Wpf;
+
+namespace TV_Player
+{
+ public partial class MainWindow : Window
+ {
+ private readonly DirectoryInfo vlcLibDirectory;
+ private VlcControl control;
+
+ public MainWindow()
+ {
+ InitializeComponent();
+ var currentAssembly = Assembly.GetEntryAssembly();
+ var currentDirectory = new FileInfo(currentAssembly.Location).DirectoryName;
+ // Default installation path of VideoLAN.LibVLC.Windows
+ vlcLibDirectory = new DirectoryInfo(Path.Combine(currentDirectory, "libvlc", IntPtr.Size == 4 ? "win-x86" : "win-x64"));
+
+ this.control = new VlcControl();
+ this.control.SourceProvider.CreatePlayer(vlcLibDirectory/* pass your player parameters here */);
+
+ Initialize();
+ }
+
+
+
+ protected override void OnClosing(CancelEventArgs e)
+ {
+ this.control?.Dispose();
+ base.OnClosing(e);
+ }
+
+ private void OnPlayButtonClick(object sender, RoutedEventArgs e)
+ {
+ //this.control?.Dispose();
+ //this.control = new VlcControl();
+ //this.ControlContainer.Content = this.control;
+ //this.control.SourceProvider.CreatePlayer(this.vlcLibDirectory);
+
+ // This can also be called before EndInit
+ this.control.SourceProvider.MediaPlayer.Log += (_, args) =>
+ {
+ string message = $"libVlc : {args.Level} {args.Message} @ {args.Module}";
+ System.Diagnostics.Debug.WriteLine(message);
+ };
+
+ control.SourceProvider.MediaPlayer.Play(new Uri("http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_surround-fix.avi"));
+ }
+
+ private void OnStopButtonClick(object sender, RoutedEventArgs e)
+ {
+ this.control?.Dispose();
+ this.control = null;
+ }
+
+ private void OnForwardButtonClick(object sender, RoutedEventArgs e)
+ {
+ if (this.control == null)
+ {
+ return;
+ }
+
+ this.control.SourceProvider.MediaPlayer.Rate = 2;
+ }
+
+ private void GetLength_Click(object sender, RoutedEventArgs e)
+ {
+ if (this.control == null)
+ {
+ return;
+ }
+
+ //GetLength.Content = this.control.SourceProvider.MediaPlayer.Length + " ms";
+ }
+
+ private void GetCurrentTime_Click(object sender, RoutedEventArgs e)
+ {
+ if (this.control == null)
+ {
+ return;
+ }
+
+ //GetCurrentTime.Content = this.control.SourceProvider.MediaPlayer.Time + " ms";
+ }
+
+ private void SetCurrentTime_Click(object sender, RoutedEventArgs e)
+ {
+ if (this.control == null)
+ {
+ return;
+ }
+
+ this.control.SourceProvider.MediaPlayer.Time = 5000;
+ //SetCurrentTime.Content = this.control.SourceProvider.MediaPlayer.Time + " ms";
+ }
+ }
+}
\ No newline at end of file
diff --git a/TV Player_old/MainWindowViewModel.cs b/TV Player_old/MainWindowViewModel.cs
new file mode 100644
index 0000000..371c267
--- /dev/null
+++ b/TV Player_old/MainWindowViewModel.cs
@@ -0,0 +1,43 @@
+using System.Windows.Controls;
+
+namespace TV_Player
+{
+ public class MainWindowViewModel
+ {
+ public MainWindowViewModel()
+ {
+ }
+
+ private async Task Initialize()
+ {
+ string m3uLink = "http://pl.da-tv.vip/a71e77fa/835b3216/tv.m3u";
+ var programs = await M3UParser.DownloadM3UFromWebAsync(m3uLink);
+ var groupedPrograms = programs.GroupBy(item => item.GroupTitle)
+ .ToDictionary(
+ group => group.Key,
+ group => group.Select(item => item).ToList()
+ );
+
+ var row = 0;
+ var column = 0;
+
+ foreach (var group in groupedPrograms)
+ {
+ var button = new GroupButton(group.Key, group.Value.Count());
+ button.TouchDown += (s, e) =>
+ {
+
+ };
+ Grid.SetRow(button, row);
+ Grid.SetColumn(button, column);
+ groupsGrid.Children.Add(button);
+ column++;
+ if (column > 4)
+ {
+ row++;
+ column = 0;
+ }
+ }
+ }
+ }
+}
diff --git a/TV Player_old/ProgramsGroupGrid.xaml b/TV Player_old/ProgramsGroupGrid.xaml
new file mode 100644
index 0000000..83d6964
--- /dev/null
+++ b/TV Player_old/ProgramsGroupGrid.xaml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TV Player_old/ProgramsGroupGrid.xaml.cs b/TV Player_old/ProgramsGroupGrid.xaml.cs
new file mode 100644
index 0000000..19a26f0
--- /dev/null
+++ b/TV Player_old/ProgramsGroupGrid.xaml.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace TV_Player
+{
+ ///
+ /// Interaction logic for ProgramsGroupGrid.xaml
+ ///
+ public partial class ProgramsGroupGrid : UserControl
+ {
+ public ProgramsGroupGrid()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/TV Player_old/TV Player.csproj b/TV Player_old/TV Player.csproj
new file mode 100644
index 0000000..3c5e77a
--- /dev/null
+++ b/TV Player_old/TV Player.csproj
@@ -0,0 +1,29 @@
+
+
+
+ WinExe
+ net8.0-windows
+ TV_Player
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Never
+
+
+
+
diff --git a/TV player.sln b/TV player.sln
new file mode 100644
index 0000000..29c741a
--- /dev/null
+++ b/TV player.sln
@@ -0,0 +1,27 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34330.188
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TV Player", "TV Player\TV Player.csproj", "{A2ADD73B-0E50-4D86-9E1B-35FB2A31F5BF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A2ADD73B-0E50-4D86-9E1B-35FB2A31F5BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A2ADD73B-0E50-4D86-9E1B-35FB2A31F5BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A2ADD73B-0E50-4D86-9E1B-35FB2A31F5BF}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {A2ADD73B-0E50-4D86-9E1B-35FB2A31F5BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A2ADD73B-0E50-4D86-9E1B-35FB2A31F5BF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A2ADD73B-0E50-4D86-9E1B-35FB2A31F5BF}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {FEE14CDB-8F69-4F66-8937-B9148BBE9088}
+ EndGlobalSection
+EndGlobal