Got WPF version work

This commit is contained in:
Vova
2024-01-18 17:42:44 +02:00
parent df51ee3ad6
commit 10b4146772
64 changed files with 866 additions and 411 deletions
+9
View File
@@ -0,0 +1,9 @@
<Application x:Class="TV_Player.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TV_Player"
>
<Application.Resources>
</Application.Resources>
</Application>
+22
View File
@@ -0,0 +1,22 @@
using DirectShowLib.BDA;
using System.Configuration;
using System.Data;
using System.Windows;
using TV_Player.ViewModels;
namespace TV_Player
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private TVPlayerViewModel _tvPlayer;
protected override void OnStartup(StartupEventArgs e)
{
_tvPlayer = new TVPlayerViewModel();
base.OnStartup(e);
}
}
}
+10
View File
@@ -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)
)]
Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

+22
View File
@@ -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;
}
}
}
+26
View File
@@ -0,0 +1,26 @@
<UserControl x:Class="TV_Player.GroupButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="200">
<Viewbox Grid.Row="1">
<Grid x:Name="ButtonBorder" Height="70" Width="150" >
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="0.4*"/>
</Grid.RowDefinitions>
<Rectangle RadiusX="15" RadiusY="15" x:Name="Border" StrokeThickness="3" Stroke="Yellow" Stretch="Fill" Grid.RowSpan="2" Fill="#FF1F1E1E"/>
<TextBlock x:Name="groupName" Text="Group name" FontSize="15" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock Grid.Row="1" FontSize="10" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center" LineStackingStrategy="BlockLineHeight" LineHeight="10">
<Run x:Name="programsFound"/>
<Run>Programs</Run>
</TextBlock>
</Grid>
</Grid>
</Viewbox>
</UserControl>
+17
View File
@@ -0,0 +1,17 @@
using System.Windows.Controls;
namespace TV_Player
{
/// <summary>
/// Interaction logic for GroupButton.xaml
/// </summary>
public partial class GroupButton : UserControl
{
public GroupButton(string groupName,int programsFound)
{
InitializeComponent();
this.groupName.Text = groupName;
this.programsFound.Text = programsFound.ToString();
}
}
}
+18
View File
@@ -0,0 +1,18 @@
<Window x:Class="TV_Player.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TV_Player"
mc:Ignorable="d"
Title="TV" Height="450" Width="800">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.Background>
<ImageBrush ImageSource="Assets/bkground.jpg" />
</Grid.Background>
<ContentControl Name="ControlContainer" Content="{Binding Control}" />
</Grid>
</Window>
+13
View File
@@ -0,0 +1,13 @@
using System.Windows;
namespace TV_Player
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
+24
View File
@@ -0,0 +1,24 @@
<UserControl x:Class="TV_Player.ProgramsGroupGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TV_Player"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid x:Name="groupsGrid">
<ScrollViewer>
<ListBox ItemsSource="{Binding Programs}"
SelectionMode="Single"
SelectedItem="{Binding SelectedItem}"
SelectionChanged="ListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
</Grid>
</UserControl>
+23
View File
@@ -0,0 +1,23 @@
using System.Windows.Controls;
namespace TV_Player
{
/// <summary>
/// Interaction logic for ProgramsGroupGrid.xaml
/// </summary>
public partial class ProgramsGroupGrid : UserControl
{
public ProgramsGroupGrid()
{
InitializeComponent();
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (DataContext is ProgramsGroupViewModel viewModel)
{
viewModel.ItemSelectedCommand.Execute(null);
}
}
}
}
+25
View File
@@ -0,0 +1,25 @@
<UserControl x:Class="TV_Player.ProgramsList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid x:Name="groupsGrid">
<ScrollViewer>
<ListBox ItemsSource="{Binding Programs}"
SelectionMode="Single"
SelectedItem="{Binding SelectedItem}"
SelectionChanged="ListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding Logo}" Width="50" Height="50"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
</Grid>
</UserControl>
+22
View File
@@ -0,0 +1,22 @@
using System.Windows.Controls;
namespace TV_Player
{
/// <summary>
/// Interaction logic for ProgramsGroupGrid.xaml
/// </summary>
public partial class ProgramsList : UserControl
{
public ProgramsList()
{
InitializeComponent();
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (DataContext is ProgramsListViewModel viewModel)
{
viewModel.ItemSelectedCommand.Execute(null);
}
}
}
}
+39
View File
@@ -0,0 +1,39 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<RootNamespace>TV_Player</RootNamespace>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<None Remove="Assets\bkGround.jpg" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="LibVLCSharp" Version="3.8.2" />
<PackageReference Include="LibVLCSharp.WPF" Version="3.8.2" />
<PackageReference Include="System.Reactive" Version="6.0.0" />
<PackageReference Include="WPFMediaKitCore" Version="0.0.3" />
</ItemGroup>
<ItemGroup>
<Resource Include="Assets\bkground.jpg">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Resource>
</ItemGroup>
<ItemGroup>
<Compile Update="VideoPlayer.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="ProgramsList.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
</Project>
+31
View File
@@ -0,0 +1,31 @@
<UserControl x:Class="TV_Player.VideoPlayer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vlc="clr-namespace:LibVLCSharp.WPF;assembly=LibVLCSharp.WPF"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
>
<Grid>
<Grid x:Name="videoPlayer">
<vlc:VideoView x:Name="VideoView" Panel.ZIndex="1">
<StackPanel Panel.ZIndex="2" Opacity="0.9"
IsHitTestVisible="True"
HorizontalAlignment="Stretch" MouseLeftButtonDown="MyUserControl_MouseDown"
TouchDown="MyUserControl_TouchDown" >
<Grid x:Name="overlayPanel" Visibility="Collapsed" >
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="Pause" HorizontalAlignment="Stretch" Click="PauseButton_Click" />
</Grid>
</StackPanel>
</vlc:VideoView>
</Grid>
</Grid>
</UserControl>
+114
View File
@@ -0,0 +1,114 @@
using LibVLCSharp.Shared;
using LibVLCSharp.WPF;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace TV_Player
{
/// <summary>
/// Interaction logic for ProgramsGroupGrid.xaml
/// </summary>
public partial class VideoPlayer : UserControl
{
private readonly DirectoryInfo vlcLibDirectory;
public static readonly DependencyProperty SourceUrlProperty =
DependencyProperty.Register(
"SourceUrl", // Name of the property
typeof(string), // Type of the property
typeof(VideoPlayer), // Type of the owner class
new PropertyMetadata(string.Empty) // Default value
);
LibVLC _libVLC;
MediaPlayer _mediaPlayer;
public string SourceUrl
{
get { return (string)GetValue(SourceUrlProperty); }
set { SetValue(SourceUrlProperty, value);}
}
public VideoPlayer()
{
InitializeComponent();
_libVLC = new LibVLC(enableDebugLogs: true);
_mediaPlayer = new MediaPlayer(_libVLC);
VideoView.Loaded += (sender, e) =>
{
VideoView.MediaPlayer = _mediaPlayer;
VideoView.MouseLeftButtonDown += VideoView_MouseLeftButtonDown;
VideoView.MediaPlayer.EnableMouseInput = false;
VideoView.PreviewMouseLeftButtonDown += VideoView_MouseLeftButtonDown;
AutoPlay();
};
Unloaded += VideoPlayer_Unloaded;
}
private void VideoView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
ToggleOverlay();
}
private void VideoPlayer_Unloaded(object sender, RoutedEventArgs e)
{
VideoView.Dispose();
}
void PauseButton_Click(object sender, RoutedEventArgs e)
{
if (VideoView.MediaPlayer.IsPlaying)
{
VideoView.MediaPlayer.Pause();
}
}
private void AutoPlay()
{
if (!VideoView.MediaPlayer.IsPlaying)
{
using (var media = new Media(_libVLC, new Uri(SourceUrl)))
VideoView.MediaPlayer.Play(media);
}
}
private void MyUserControl_MouseDown(object sender, MouseButtonEventArgs e)
{
ToggleOverlay();
}
private void MyUserControl_TouchDown(object sender, TouchEventArgs e)
{
ToggleOverlay();
}
private void ToggleOverlay()
{
if (overlayPanel.Visibility == Visibility.Visible)
{
HideOverlay();
}
else
{
ShowOverlay();
}
}
public void ShowOverlay()
{
overlayPanel.Visibility = Visibility.Visible;
}
public void HideOverlay()
{
overlayPanel.Visibility = Visibility.Collapsed;
}
}
}
+8
View File
@@ -0,0 +1,8 @@
namespace TV_Player
{
public class GroupInfo
{
public string Name { get; set; }
public int Count { get; set; }
}
}
+14
View File
@@ -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; }
}
}
+101
View File
@@ -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<List<M3UInfo>> DownloadM3UFromWebAsync(string url)
{
List<M3UInfo> playlistItems = new List<M3UInfo>();
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<M3UInfo> ParseM3UFromString(string content)
{
List<M3UInfo> playlistItems = new List<M3UInfo>();
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=""(?<CUID>.*?)"" number=""(?<Number>.*?)"" tvg-id=""(?<TvgID>.*?)"" tvg-name=""(?<TvgName>.*?)"".*?tvg-logo=""(?<Logo>.*?)"" group-title=""(?<GroupTitle>.*?)""[^,]*,(?<Name>.*)[^\r](?<URL>.*)$";
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;
}
}
}
+23
View File
@@ -0,0 +1,23 @@
using System.Windows.Controls;
namespace TV_Player
{
public class MainViewModel : ObservableViewModelBase
{
private ContentControl _control;
public ContentControl Control
{
get => _control;
set => SetProperty(ref _control, value);
}
public MainViewModel()
{
var vm = new ProgramsGroupViewModel();
var control = new ProgramsGroupGrid();
control.DataContext = vm;
Control = control;
}
}
}
@@ -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));
/// <summary>
/// Set a property and raise a property changed event if it has changed
/// </summary>
protected bool SetProperty<T>(ref T property, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(property, value))
{
return false;
}
property = value;
RaisePropertyChanged(propertyName);
return true;
}
}
}
@@ -0,0 +1,48 @@
using System.Windows.Input;
namespace TV_Player
{
public class PlayerViewModel: ObservableViewModelBase
{
private readonly M3UInfo _currentProgram;
private string _urlSource;
public string URLSource
{
get => _urlSource;
set => SetProperty(ref _urlSource, value);
}
public GroupInfo SelectedItem { get; set; }
public ICommand PlayCommand { get; }
public PlayerViewModel(M3UInfo selectedProgram)
{
_currentProgram = selectedProgram;
//PlayM3U8(_currentProgram.Url);
//_libVLC = new LibVLC();
//_mediaPlayer = new MediaPlayer(new Media(_libVLC, new Uri(_currentProgram.Url)));
//_mediaPlayer.Play();
//PlayCommand = new Command(OnPlayButtonClicked);
}
private void OnPlayButtonClicked()
{
PlayM3U8(_currentProgram.Url);
}
private void PlayM3U8(string url)
{
try
{
URLSource = _currentProgram.Url;
}
catch (Exception ex)
{
// Handle exceptions
}
}
}
}
+39
View File
@@ -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 ReplaySubject<List<M3UInfo>> programsSubject = new ReplaySubject<List<M3UInfo>>();
private readonly ReplaySubject<List<GroupInfo>> groupsSubject = new ReplaySubject<List<GroupInfo>>();
public IObservable<List<M3UInfo>> AllPrograms => programsSubject;
public IObservable<List<GroupInfo>> 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);
}
}
}
@@ -0,0 +1,36 @@
using CommunityToolkit.Mvvm.Input;
using System.Windows.Input;
using TV_Player.ViewModels;
namespace TV_Player
{
public class ProgramsGroupViewModel : ObservableViewModelBase
{
private List<GroupInfo> _programs;
public List<GroupInfo> Programs
{
get => _programs;
set => SetProperty(ref _programs, value);
}
public GroupInfo SelectedItem { get; set; }
public ICommand ItemSelectedCommand { get; }
public ProgramsGroupViewModel()
{
ItemSelectedCommand = new RelayCommand(OnItemSelected);
ProgramsData.Instance.GroupsInformation.Subscribe(x=>Programs = x);
}
private void OnItemSelected()
{
//var navigation = (INavigation)Application.Current.MainPage.Navigation;
var programListViewModel = new ProgramsListViewModel(SelectedItem);
var conrtrol = new ProgramsList();
TVPlayerViewModel.Instance.SetPageContext(conrtrol, programListViewModel);
}
}
}
@@ -0,0 +1,45 @@
using CommunityToolkit.Mvvm.Input;
using System.Windows.Input;
using TV_Player.ViewModels;
namespace TV_Player
{
public class ProgramsListViewModel : ObservableViewModelBase
{
private List<M3UInfo> _programs;
public List<M3UInfo> Programs
{
get => _programs;
set => SetProperty(ref _programs, value);
}
public M3UInfo SelectedItem { get; set; }
public ICommand ItemSelectedCommand { get; }
public ProgramsListViewModel(GroupInfo groupInfo)
{
ItemSelectedCommand = new RelayCommand(OnItemSelected);
ProgramsData.Instance.AllPrograms.Subscribe(x=>Programs = x.Where(p=>p.GroupTitle== groupInfo.Name).ToList());
}
private void OnItemSelected()
{
var playerViewModel = new PlayerViewModel(SelectedItem);
var conrtrol = new VideoPlayer();
conrtrol.SourceUrl = SelectedItem.Url;
TVPlayerViewModel.Instance.SetPageContext(conrtrol, playerViewModel);
//var navigation = (INavigation)Application.Current.MainPage.Navigation;
//var playerViewModel = new PlayerViewModel(SelectedItem);
//// Create a new SecondPage and set its BindingContext to the ViewModel
//var playerPage = new PlayerPage
//{
// BindingContext = playerViewModel
//};
//// Navigate to the OtherPage
//navigation.PushAsync(playerPage);
}
}
}
+33
View File
@@ -0,0 +1,33 @@
using System.Windows.Input;
namespace TV_Player.ViewModels
{
//public class RelayCommand : ICommand
//{
// private readonly Action _execute;
// private readonly Func<bool> _canExecute;
// public event EventHandler CanExecuteChanged;
// public RelayCommand(Action execute, Func<bool> canExecute = null)
// {
// _execute = execute ?? throw new ArgumentNullException(nameof(execute));
// _canExecute = canExecute;
// }
// public bool CanExecute(object parameter)
// {
// return _canExecute == null || _canExecute();
// }
// public void Execute(object parameter)
// {
// _execute();
// }
// public void RaiseCanExecuteChanged()
// {
// CanExecuteChanged?.Invoke(this, EventArgs.Empty);
// }
//}
}
@@ -0,0 +1,37 @@
using System.Windows.Controls;
namespace TV_Player.ViewModels
{
public class TVPlayerViewModel
{
private readonly MainViewModel _mainViewModel;
private static TVPlayerViewModel _instance;
public static TVPlayerViewModel Instance
{
get
{
if(_instance==null)
_instance = new TVPlayerViewModel();
return _instance;
}
}
public TVPlayerViewModel()
{
_mainViewModel = new MainViewModel();
var mainWindow=new MainWindow();
mainWindow.DataContext = _mainViewModel;
mainWindow.Show();
_instance = this;
}
public void SetPageContext(ContentControl control, object viewModel)
{
control.DataContext = viewModel;
_mainViewModel.Control = control;
}
}
}