add close button
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<ResourceDictionary Source="/Assets/GroupButtonStyle.xaml"/>
|
<ResourceDictionary Source="/Assets/AppStyle.xaml"/>
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
|
|||||||
@@ -45,6 +45,43 @@ c-0.781-0.781-0.788-2.047-0.007-2.828L51.438,14.43c1.754-1.755,1.753-4.61-0.001-
|
|||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="ButtonConfirm" TargetType="{x:Type Button}">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type Button}">
|
||||||
|
<Border Background="LightGreen" Height="50" Width="50" CornerRadius="300">
|
||||||
|
<Path Width="40" Height="40" Fill="Gray" Stretch="Fill" Data="M50.131649,63.741954 C47.860649,63.741954 45.726649,62.857954 44.120649,61.252954 L17.736,42.258 C16.09,40.613 15.19,38.337 15.257,36.003 15.189,33.666 16.091317,31.389 17.737317,29.742 L29.656036,13.830155 C31.261036,12.225155 33.393719,11.341155 35.664719,11.341155 37.935719,11.341155 40.069719,12.225155 41.674719,13.830155 44.988719,17.144155 44.988719,22.537155 41.674719,25.851155 L35.519,36 56.141649,49.230954 C59.455649,52.544954 59.455649,57.937954 56.141649,61.251954 54.535649,62.857954 52.401649,63.741954 50.131649,63.741954 z M35.664719,15.341155 C34.462719,15.341155 33.332719,15.809155 32.482719,16.658155 L21.038,32.57 C20.147,33.463 20.205,34.654 20.205,35.925 20.205,35.976 20.205,36.026 20.205,36.076 20.205,37.347 20.147,38.537 21.038,39.429 L47.186649,58.423954 C48.036649,59.273954 49.048649,59.740954 50.249649,59.740954 51.452649,59.740954 52.522649,59.272954 53.372649,58.423954 55.127649,56.668954 55.097649,53.813954 53.342649,52.058954 L31.292,37.414 C30.511,36.633 30.504,35.367 31.285,34.586 L38.850719,23.024155 C40.604719,21.269155 40.603719,18.414155 38.849719,16.659155 37.999719,15.809155 36.866719,15.341155 35.664719,15.341155 z" >
|
||||||
|
<Path.RenderTransform>
|
||||||
|
<TransformGroup>
|
||||||
|
<TranslateTransform X="-42"/>
|
||||||
|
<RotateTransform Angle="-90"/>
|
||||||
|
</TransformGroup>
|
||||||
|
</Path.RenderTransform>
|
||||||
|
</Path>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="ButtonClose" TargetType="{x:Type Button}">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type Button}">
|
||||||
|
<Border Background="Red" Height="50" Width="50" CornerRadius="300">
|
||||||
|
<Path Fill="#FFF4F4F5" HorizontalAlignment="Center" Height="35" Stroke="Black" Stretch="Fill" VerticalAlignment="Center" Width="30">
|
||||||
|
<Path.Data>
|
||||||
|
<PathGeometry Figures="M37.037194,7.2021995 L26.096188,22.041976 14.061081,7.7110519 11.032645,10.623983 23.403814,25.437079 12.403519,38.730884 16.26689,41.383471 26.112258,28.966796 36.580749,41.639484 40.194871,38.695324 28.770656,25.593375 40.319496,9.9857232 z"/>
|
||||||
|
</Path.Data>
|
||||||
|
</Path>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Style x:Key="ButtonUp" TargetType="{x:Type Button}">
|
<Style x:Key="ButtonUp" TargetType="{x:Type Button}">
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:TV_Player"
|
xmlns:local="clr-namespace:TV_Player"
|
||||||
mc:Ignorable="d" WindowStyle="{Binding CurrentWindowStyle}" WindowState="{Binding CurrentWindowState}"
|
mc:Ignorable="d" WindowStyle="None" WindowState="{Binding CurrentWindowState}"
|
||||||
Title="TV" Height="450" Width="800">
|
Title="TV" Height="450" Width="800">
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverterKey"/>
|
<local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverterKey"/>
|
||||||
@@ -26,11 +26,13 @@
|
|||||||
<ColumnDefinition Width="80"/>
|
<ColumnDefinition Width="80"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
<ColumnDefinition Width="80"/>
|
<ColumnDefinition Width="80"/>
|
||||||
|
<ColumnDefinition Width="80"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Button Height="70" Width="70" Margin="10,0,0,0" Style="{DynamicResource ButtonGear}" Command="{Binding SettingsCommand}" />
|
<Button Height="70" Width="70" Margin="10,0,0,0" Style="{DynamicResource ButtonGear}" Command="{Binding SettingsCommand}" />
|
||||||
<Button Grid.Column="1" Height="70" Width="70" Margin="10,0,0,0" Style="{DynamicResource ButtonBack}" Command="{Binding BackCommand}" />
|
<Button Grid.Column="1" Height="70" Width="70" Margin="10,0,0,0" Style="{DynamicResource ButtonBack}" Command="{Binding BackCommand}" />
|
||||||
<TextBlock Grid.Column="2" FontSize="30" Foreground="White" Text="{Binding TopPanelTitle}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
<TextBlock Grid.Column="2" FontSize="30" Foreground="White" Text="{Binding TopPanelTitle}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
<Button Grid.Column="4" Height="70" Width="70" Margin="10,0,0,0" Style="{DynamicResource ButtonFullScreen}" Command="{Binding FullscreenCommand}" />
|
<Button Grid.Column="3" Height="70" Width="70" Margin="10,0,0,0" Style="{DynamicResource ButtonFullScreen}" Command="{Binding FullscreenCommand}" />
|
||||||
|
<Button Grid.Column="4" Height="70" Width="70" Margin="10,0,0,0" Style="{DynamicResource ButtonClose}" Command="{Binding CloseAppCommand}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<ContentControl Grid.Row="1" Name="ControlContainer" Content="{Binding Control}" />
|
<ContentControl Grid.Row="1" Name="ControlContainer" Content="{Binding Control}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -12,7 +12,8 @@
|
|||||||
<CheckBox Margin="10" Foreground="White" FontSize="25" IsChecked="{Binding StartLastScreen}">Запоминать последний выбор</CheckBox>
|
<CheckBox Margin="10" Foreground="White" FontSize="25" IsChecked="{Binding StartLastScreen}">Запоминать последний выбор</CheckBox>
|
||||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||||
<Button Grid.Column="1" Height="70" Width="70" Margin="10,0,50,0" Style="{DynamicResource ButtonBack}" Command="{Binding BackCommand}" />
|
<Button Grid.Column="1" Height="70" Width="70" Margin="10,0,50,0" Style="{DynamicResource ButtonBack}" Command="{Binding BackCommand}" />
|
||||||
<Button HorizontalAlignment="Center" FontSize="25" Command="{Binding SaveCommand}">Сохранить</Button>
|
<Button HorizontalAlignment="Center" Height="70" Width="70" Style="{DynamicResource ButtonConfirm}" Command="{Binding SaveCommand}" />
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -37,14 +37,8 @@ namespace TV_Player
|
|||||||
set => SetProperty(ref _currentWindowState, value);
|
set => SetProperty(ref _currentWindowState, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private WindowStyle _currentWindowStyle;
|
|
||||||
public WindowStyle CurrentWindowStyle
|
|
||||||
{
|
|
||||||
get => _currentWindowStyle;
|
|
||||||
set => SetProperty(ref _currentWindowStyle, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ICommand FullscreenCommand { get; }
|
public ICommand FullscreenCommand { get; }
|
||||||
|
public ICommand CloseAppCommand { get; }
|
||||||
|
|
||||||
public Action ButtonBackAction { get; set; }
|
public Action ButtonBackAction { get; set; }
|
||||||
public ICommand BackCommand { get; }
|
public ICommand BackCommand { get; }
|
||||||
@@ -57,24 +51,26 @@ namespace TV_Player
|
|||||||
BackCommand = new RelayCommand(OnButtonBackClick);
|
BackCommand = new RelayCommand(OnButtonBackClick);
|
||||||
FullscreenCommand = new RelayCommand(OnFullSctreenButtonClick);
|
FullscreenCommand = new RelayCommand(OnFullSctreenButtonClick);
|
||||||
SettingsCommand = new RelayCommand(OnSettingsButtonClick);
|
SettingsCommand = new RelayCommand(OnSettingsButtonClick);
|
||||||
|
CloseAppCommand = new RelayCommand(OnCloseAppButtonClick);
|
||||||
CurrentWindowStyle = WindowStyle.SingleBorderWindow;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnFullSctreenButtonClick()
|
public void OnFullSctreenButtonClick()
|
||||||
{
|
{
|
||||||
if (CurrentWindowStyle == WindowStyle.SingleBorderWindow)
|
if (CurrentWindowState == WindowState.Normal)
|
||||||
{
|
{
|
||||||
CurrentWindowStyle = WindowStyle.None;
|
|
||||||
CurrentWindowState = WindowState.Maximized;
|
CurrentWindowState = WindowState.Maximized;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CurrentWindowStyle = WindowStyle.SingleBorderWindow;
|
|
||||||
CurrentWindowState = WindowState.Normal;
|
CurrentWindowState = WindowState.Normal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnCloseAppButtonClick()
|
||||||
|
{
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnButtonBackClick()
|
private void OnButtonBackClick()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||||
xmlns:local="clr-namespace:TV_Player.MAUI"
|
xmlns:local="clr-namespace:TV_Player.MAUI"
|
||||||
Shell.FlyoutBehavior="Disabled">
|
Shell.FlyoutBehavior="Disabled"
|
||||||
|
Background="DarkGray">
|
||||||
|
|
||||||
<ShellContent
|
<ShellContent
|
||||||
ContentTemplate="{DataTemplate local:MainPage}"
|
ContentTemplate="{DataTemplate local:MainPage}"
|
||||||
|
|||||||
@@ -2,9 +2,11 @@
|
|||||||
{
|
{
|
||||||
public partial class AppShell : Shell
|
public partial class AppShell : Shell
|
||||||
{
|
{
|
||||||
|
private TVPlayerViewModel _tvPlayer;
|
||||||
public AppShell()
|
public AppShell()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
_tvPlayer = new TVPlayerViewModel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-11
@@ -15,20 +15,24 @@
|
|||||||
SelectedItem="{Binding SelectedItem}"
|
SelectedItem="{Binding SelectedItem}"
|
||||||
SelectionChangedCommand="{Binding ItemSelectedCommand}">
|
SelectionChangedCommand="{Binding ItemSelectedCommand}">
|
||||||
<CollectionView.ItemTemplate>
|
<CollectionView.ItemTemplate>
|
||||||
<DataTemplate x:DataType="local:M3UInfo">
|
<DataTemplate x:DataType="local:GroupInfo">
|
||||||
<Label Text="{Binding Name}"/>
|
<Border x:Name="ButtonBorder">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="0.4*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Rectangle RadiusX="15" RadiusY="15" x:Name="Border" StrokeThickness="2" Stroke="Yellow" Grid.RowSpan="2" Fill="#B0000000"/>
|
||||||
|
<Label x:Name="groupName" Text="{TemplateBinding GroupName}" FontSize="15" TextColor="White" HorizontalOptions="Center" VerticalOptions="Center"/>
|
||||||
|
<HorizontalStackLayout Grid.Row="1" >
|
||||||
|
<Label Text="{TemplateBinding ProgramsCount}" FontSize="10" TextColor="White" HorizontalOptions="Center" VerticalOptions="Center" LineHeight="10"/>
|
||||||
|
<Label FontSize="10" TextColor="White" HorizontalOptions="Center" VerticalOptions="Center" LineHeight="10">программ</Label >
|
||||||
|
</HorizontalStackLayout>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</CollectionView.ItemTemplate>
|
</CollectionView.ItemTemplate>
|
||||||
</CollectionView>
|
</CollectionView>
|
||||||
|
|
||||||
<!--<Label
|
|
||||||
Text="Welcome to .NET Multi-platform App UI"
|
|
||||||
SemanticProperties.HeadingLevel="Level2"
|
|
||||||
SemanticProperties.Description="Welcome to dot net Multi platform App U I"
|
|
||||||
FontSize="18"
|
|
||||||
HorizontalOptions="Center" />-->
|
|
||||||
|
|
||||||
|
|
||||||
</VerticalStackLayout>
|
</VerticalStackLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using CommunityToolkit.Maui;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using CommunityToolkit.Maui;
|
||||||
|
|
||||||
namespace TV_Player.MAUI
|
namespace TV_Player.MAUI
|
||||||
{
|
{
|
||||||
@@ -17,10 +17,6 @@ namespace TV_Player.MAUI
|
|||||||
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
|
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
|
||||||
});
|
});
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
builder.Logging.AddDebug();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return builder.Build();
|
return builder.Build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
using LibVLCSharp.Shared;
|
|
||||||
|
|
||||||
namespace TV_Player.MAUI
|
namespace TV_Player.MAUI
|
||||||
{
|
{
|
||||||
public class MediaViewer : ContentView
|
public class MediaViewer : ContentView
|
||||||
{
|
{
|
||||||
private LibVLC _libVLC;
|
//private MediaPlayer _mediaPlayer;
|
||||||
private MediaPlayer _mediaPlayer;
|
|
||||||
|
|
||||||
public static BindableProperty StreamUrlProperty = BindableProperty.Create(nameof(StreamUrl)
|
public static BindableProperty StreamUrlProperty = BindableProperty.Create(nameof(StreamUrl)
|
||||||
, typeof(string)
|
, typeof(string)
|
||||||
@@ -29,16 +27,13 @@ namespace TV_Player.MAUI
|
|||||||
|
|
||||||
private void InitializeMediaPlayer()
|
private void InitializeMediaPlayer()
|
||||||
{
|
{
|
||||||
_libVLC = new LibVLC();
|
|
||||||
_mediaPlayer = new MediaPlayer(_libVLC);
|
|
||||||
// var media = new Media(_libVLC, new Uri("http://ost.da-tv.vip/uPVtzdGJfdG9rZW5dIiwibCI6ImE3MWU3N2ZhIiwicCI6ImE3MWU3N2ZhODM1YjMyMTYiLCJjIjoiNDk3IiwidCI6ImUzNjAwZTEwZmFmMGVhYjhhYWY1YTU2YzRkN2VjZTE5IiwiZCI6IjIzMTQ2IiwiciI6IjIzMDM4IiwibSI6InR2IiwiZHQiOiIwIn0eyJ1IjoiaHR0cDovLzQ1LjkzLjQ2LjI3Ojg4ODcvODM2MS92aWRlby5tM3U4P3Rva2V/video.m3u8"));
|
// var media = new Media(_libVLC, new Uri("http://ost.da-tv.vip/uPVtzdGJfdG9rZW5dIiwibCI6ImE3MWU3N2ZhIiwicCI6ImE3MWU3N2ZhODM1YjMyMTYiLCJjIjoiNDk3IiwidCI6ImUzNjAwZTEwZmFmMGVhYjhhYWY1YTU2YzRkN2VjZTE5IiwiZCI6IjIzMTQ2IiwiciI6IjIzMDM4IiwibSI6InR2IiwiZHQiOiIwIn0eyJ1IjoiaHR0cDovLzQ1LjkzLjQ2LjI3Ojg4ODcvODM2MS92aWRlby5tM3U4P3Rva2V/video.m3u8"));
|
||||||
//_mediaPlayer.Play();
|
//_mediaPlayer.Play();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Play()
|
public void Play()
|
||||||
{
|
{
|
||||||
var media = new Media(_libVLC, new Uri("http://ost.da-tv.vip/uPVtzdGJfdG9rZW5dIiwibCI6ImE3MWU3N2ZhIiwicCI6ImE3MWU3N2ZhODM1YjMyMTYiLCJjIjoiNDk3IiwidCI6ImUzNjAwZTEwZmFmMGVhYjhhYWY1YTU2YzRkN2VjZTE5IiwiZCI6IjIzMTQ2IiwiciI6IjIzMDM4IiwibSI6InR2IiwiZHQiOiIwIn0eyJ1IjoiaHR0cDovLzQ1LjkzLjQ2LjI3Ojg4ODcvODM2MS92aWRlby5tM3U4P3Rva2V/video.m3u8"));
|
|
||||||
_mediaPlayer.Play(media);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||||
x:Class="TV_Player.MAUI.PlayerPage"
|
x:Class="TV_Player.MAUI.PlayerPage"
|
||||||
xmlns:local="clr-namespace:TV_Player.MAUI"
|
xmlns:local="clr-namespace:TV_Player.MAUI"
|
||||||
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
|
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
|
||||||
Title="PlayerPage"
|
Title="PlayerPage"
|
||||||
xmlns:vlc="clr-namespace:LibVLCSharp.WPF;assembly=LibVLCSharp.WPF"
|
>
|
||||||
Loaded="ContentPage_Loaded">
|
|
||||||
|
|
||||||
<StackLayout>
|
<StackLayout>
|
||||||
<!--<toolkit:MediaElement x:Name="mediaElement"
|
<toolkit:MediaElement x:Name="mediaElement"/>
|
||||||
ShouldAutoPlay="True"
|
|
||||||
ShouldShowPlaybackControls="True"
|
|
||||||
Source="http://ost.da-tv.vip/uPVtzdGJfdG9rZW5dIiwibCI6ImE3MWU3N2ZhIiwicCI6ImE3MWU3N2ZhODM1YjMyMTYiLCJjIjoiNDk3IiwidCI6ImUzNjAwZTEwZmFmMGVhYjhhYWY1YTU2YzRkN2VjZTE5IiwiZCI6IjIzMTQ2IiwiciI6IjIzMDM4IiwibSI6InR2IiwiZHQiOiIwIn0eyJ1IjoiaHR0cDovLzQ1LjkzLjQ2LjI3Ojg4ODcvODM2MS92aWRlby5tM3U4P3Rva2V/video.m3u8"
|
|
||||||
HeightRequest="300"
|
|
||||||
WidthRequest="400"
|
|
||||||
/>-->
|
|
||||||
<!--<local:MediaViewer x:Name="libVLCSharpView" WidthRequest="300" HeightRequest="300" HorizontalOptions="CenterAndExpand" StreamUrl="{Binding URLSource,Source={x:Reference MyCustomView}}"/>-->
|
|
||||||
<vlc:VideoView x:Name="VideoView" Panel.ZIndex="1"/>
|
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
|
|
||||||
</ContentPage>
|
</ContentPage>
|
||||||
|
|||||||
@@ -1,111 +1,78 @@
|
|||||||
using LibVLCSharp.Shared;
|
|
||||||
|
|
||||||
namespace TV_Player.MAUI;
|
namespace TV_Player.MAUI;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Timers;
|
||||||
|
|
||||||
|
|
||||||
public partial class PlayerPage : ContentPage
|
public partial class PlayerPage : ContentPage
|
||||||
{
|
{
|
||||||
public static BindableProperty StreamUrlProperty = BindableProperty.Create(nameof(StreamUrl)
|
|
||||||
, typeof(string)
|
private const string StreamUrl = "http://ost.da-tv.vip/uPVtzdGJfdG9rZW5dIiwibCI6ImE3MWU3N2ZhIiwicCI6ImE3MWU3N2ZhODM1YjMyMTYiLCJjIjoiOTcyIiwidCI6ImUzNjAwZTEwZmFmMGVhYjhhYWY1YTU2YzRkN2VjZTE5IiwiZCI6IjIzMTQ2IiwiciI6IjIzMDM4IiwibSI6InR2IiwiZHQiOiIwIn0eyJ1IjoiaHR0cDovLzQ1LjkzLjQ2LjI3Ojg4ODcvODQwMC92aWRlby5tM3U4P3Rva2V/tracks-v1a1/mono.m3u8?cid=972&did=23146&m=1&rid=23038&token=e3600e10faf0eab8aaf5a56c4d7ece19";
|
||||||
, typeof(MediaViewer)
|
//MediaPlayer _mediaPlayer;
|
||||||
, ""
|
private const int RefreshIntervalMs = 1000; // Refresh interval in milliseconds
|
||||||
, defaultBindingMode: BindingMode.TwoWay);
|
private readonly string tempFilePath;
|
||||||
|
private Timer timer;
|
||||||
|
|
||||||
public string StreamUrl
|
public PlayerPage()
|
||||||
{
|
|
||||||
get => (string)GetValue(StreamUrlProperty);
|
|
||||||
set
|
|
||||||
{
|
|
||||||
SetValue(StreamUrlProperty, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LibVLC _libVLC;
|
|
||||||
MediaPlayer _mediaPlayer;
|
|
||||||
|
|
||||||
|
|
||||||
public VideoPlayer()
|
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
_libVLC = new LibVLC(enableDebugLogs: true);
|
tempFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "temp_media.mp4");
|
||||||
_mediaPlayer = new MediaPlayer(_libVLC);
|
StartStreaming();
|
||||||
|
}
|
||||||
|
|
||||||
VideoView.Loaded += (sender, e) =>
|
private void StartStreaming()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
VideoView.MediaPlayer = _mediaPlayer;
|
// Initialize the timer
|
||||||
VideoView.MouseLeftButtonDown += VideoView_MouseLeftButtonDown;
|
timer = new Timer(RefreshIntervalMs);
|
||||||
VideoView.MediaPlayer.EnableMouseInput = false;
|
timer.Elapsed += async (sender, e) => await UpdateTempFile();
|
||||||
VideoView.PreviewMouseLeftButtonDown += VideoView_MouseLeftButtonDown;
|
timer.AutoReset = true;
|
||||||
AutoPlay();
|
timer.Start();
|
||||||
};
|
}
|
||||||
Unloaded += VideoPlayer_Unloaded;
|
catch (Exception ex)
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
Console.WriteLine($"Error starting stream: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AutoPlay()
|
private async Task UpdateTempFile()
|
||||||
{
|
{
|
||||||
if (!VideoView.MediaPlayer.IsPlaying)
|
try
|
||||||
{
|
{
|
||||||
|
// Download the stream data
|
||||||
|
byte[] streamData = await DownloadStreamData(StreamUrl);
|
||||||
|
|
||||||
using (var media = new Media(_libVLC, new Uri(SourceUrl)))
|
// Write the stream data to the temporary file
|
||||||
VideoView.MediaPlayer.Play(media);
|
if (streamData != null)
|
||||||
|
{
|
||||||
|
await File.WriteAllBytesAsync(tempFilePath, streamData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error updating temporary file: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<byte[]> DownloadStreamData(string streamUrl)
|
||||||
private void MyUserControl_MouseDown(object sender, MouseButtonEventArgs e)
|
|
||||||
{
|
{
|
||||||
ToggleOverlay();
|
using (HttpClient client = new HttpClient())
|
||||||
}
|
|
||||||
|
|
||||||
private void MyUserControl_TouchDown(object sender, TouchEventArgs e)
|
|
||||||
{
|
|
||||||
ToggleOverlay();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ToggleOverlay()
|
|
||||||
{
|
|
||||||
if (overlayPanel.Visibility == Visibility.Visible)
|
|
||||||
{
|
{
|
||||||
HideOverlay();
|
// Download the stream asynchronously
|
||||||
}
|
return await client.GetByteArrayAsync(streamUrl);
|
||||||
else
|
|
||||||
{
|
|
||||||
ShowOverlay();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShowOverlay()
|
protected override void OnAppearing()
|
||||||
{
|
{
|
||||||
overlayPanel.Visibility = Visibility.Visible;
|
base.OnAppearing();
|
||||||
|
// Set the MediaElement source to the temporary file when the page appears
|
||||||
|
mediaElement.Source = tempFilePath;
|
||||||
|
mediaElement.ShouldAutoPlay = true; // Auto-play the media
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void HideOverlay()
|
|
||||||
{
|
|
||||||
overlayPanel.Visibility = Visibility.Collapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
VideoView.MediaPlayer?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -46,23 +46,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CommunityToolkit.Maui.MediaElement" Version="3.0.1" />
|
<PackageReference Include="CommunityToolkit.Maui.MediaElement" Version="3.1.0" />
|
||||||
<PackageReference Include="LibVLCSharp" Version="3.8.2" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
|
<PackageReference Include="System.IO" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Reactive" Version="6.0.0" />
|
<PackageReference Include="System.Reactive" Version="6.0.0" />
|
||||||
<PackageReference Include="VideoLAN.LibVLC.Windows" Version="3.0.20" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0-ios'">
|
|
||||||
<PackageReference Include="CommunityToolkit.Maui">
|
|
||||||
<Version>7.0.1</Version>
|
|
||||||
</PackageReference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0-windows10.0.19041.0'">
|
|
||||||
<PackageReference Include="CommunityToolkit.Maui">
|
|
||||||
<Version>7.0.1</Version>
|
|
||||||
</PackageReference>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -86,4 +73,11 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Update="Microsoft.Maui.Controls" Version="8.0.20" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Update="Microsoft.Maui.Controls.Compatibility" Version="8.0.20" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
namespace TV_Player.MAUI
|
namespace TV_Player.MAUI
|
||||||
{
|
{
|
||||||
|
[Serializable]
|
||||||
public class GroupInfo
|
public class GroupInfo
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|||||||
@@ -1,14 +1,34 @@
|
|||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
namespace TV_Player.MAUI
|
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 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 client = new HttpClient())
|
||||||
using (var request = new HttpRequestMessage())
|
using (var request = new HttpRequestMessage())
|
||||||
{
|
{
|
||||||
@@ -18,14 +38,84 @@ namespace TV_Player.MAUI
|
|||||||
var response = await client.GetAsync(url);
|
var response = await client.GetAsync(url);
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
string responseBody = await response.Content.ReadAsStringAsync();
|
string responseBody = await response.Content.ReadAsStringAsync();
|
||||||
|
epgChannels = ParseEpg(responseBody);
|
||||||
// Parse M3U content
|
|
||||||
playlistItems = ParseM3UFromString(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);
|
string[] parts = input.Split(separator);
|
||||||
|
|
||||||
@@ -43,10 +133,10 @@ namespace TV_Player.MAUI
|
|||||||
return parts;
|
return parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<M3UInfo> ParseM3UFromString(string content)
|
private static (List<M3UInfo> programList, string programGuide) ParseM3UFromString(string content)
|
||||||
{
|
{
|
||||||
List<M3UInfo> playlistItems = new List<M3UInfo>();
|
List<M3UInfo> playlistItems = new List<M3UInfo>();
|
||||||
|
string programGuideLink = string.Empty;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var m3u = SplitStringBeforeSeparator(content, "#EXT");
|
var m3u = SplitStringBeforeSeparator(content, "#EXT");
|
||||||
@@ -60,6 +150,10 @@ namespace TV_Player.MAUI
|
|||||||
playlistItems.Add(m3uInfo);
|
playlistItems.Add(m3uInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (line.StartsWith("#EXTM3U"))
|
||||||
|
{
|
||||||
|
programGuideLink=ExtractXtvgUrl(line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -67,11 +161,10 @@ namespace TV_Player.MAUI
|
|||||||
Console.WriteLine("Error reading M3U file: " + ex.Message);
|
Console.WriteLine("Error reading M3U file: " + ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return playlistItems;
|
return (playlistItems,programGuideLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool TryParseM3ULine(string m3uLine, out M3UInfo? info)
|
||||||
static bool TryParseM3ULine(string m3uLine, out M3UInfo? info)
|
|
||||||
{
|
{
|
||||||
info = null;
|
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>.*)$";
|
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;
|
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,6 +4,7 @@ namespace TV_Player.MAUI
|
|||||||
{
|
{
|
||||||
public class MainViewModel : ObservableViewModelBase
|
public class MainViewModel : ObservableViewModelBase
|
||||||
{
|
{
|
||||||
|
private IDisposable _groupsSubscriber;
|
||||||
private List<GroupInfo> _programs;
|
private List<GroupInfo> _programs;
|
||||||
public List<GroupInfo> Programs
|
public List<GroupInfo> Programs
|
||||||
{
|
{
|
||||||
@@ -17,7 +18,7 @@ namespace TV_Player.MAUI
|
|||||||
public MainViewModel()
|
public MainViewModel()
|
||||||
{
|
{
|
||||||
ItemSelectedCommand = new Command(OnItemSelected);
|
ItemSelectedCommand = new Command(OnItemSelected);
|
||||||
ProgramsData.Instance.GroupsInformation.Subscribe(x=>Programs = x);
|
_groupsSubscriber = TVPlayerViewModel.Instance.PlaylistData.GroupsInformation.Subscribe(x => Programs = x);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnItemSelected()
|
private void OnItemSelected()
|
||||||
@@ -33,6 +34,8 @@ namespace TV_Player.MAUI
|
|||||||
};
|
};
|
||||||
// Navigate to the OtherPage
|
// Navigate to the OtherPage
|
||||||
navigation.PushAsync(programPage);
|
navigation.PushAsync(programPage);
|
||||||
|
|
||||||
|
_groupsSubscriber.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using LibVLCSharp.Shared;
|
using System.Windows.Input;
|
||||||
using System.Windows.Input;
|
|
||||||
|
|
||||||
namespace TV_Player.MAUI
|
namespace TV_Player.MAUI
|
||||||
{
|
{
|
||||||
@@ -26,6 +25,7 @@ namespace TV_Player.MAUI
|
|||||||
//_libVLC = new LibVLC();
|
//_libVLC = new LibVLC();
|
||||||
//_mediaPlayer = new MediaPlayer(new Media(_libVLC, new Uri(_currentProgram.Url)));
|
//_mediaPlayer = new MediaPlayer(new Media(_libVLC, new Uri(_currentProgram.Url)));
|
||||||
//_mediaPlayer.Play();
|
//_mediaPlayer.Play();
|
||||||
|
URLSource = _currentProgram.Url;
|
||||||
PlayCommand = new Command(OnPlayButtonClicked);
|
PlayCommand = new Command(OnPlayButtonClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ namespace TV_Player.MAUI
|
|||||||
{
|
{
|
||||||
URLSource = _currentProgram.Url;
|
URLSource = _currentProgram.Url;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch
|
||||||
{
|
{
|
||||||
// Handle exceptions
|
// Handle exceptions
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace TV_Player.MAUI
|
|||||||
{
|
{
|
||||||
public class ProgramViewModel : ObservableViewModelBase
|
public class ProgramViewModel : ObservableViewModelBase
|
||||||
{
|
{
|
||||||
|
private IDisposable _programSubscriber;
|
||||||
private List<M3UInfo> _programs;
|
private List<M3UInfo> _programs;
|
||||||
public List<M3UInfo> Programs
|
public List<M3UInfo> Programs
|
||||||
{
|
{
|
||||||
@@ -17,7 +18,7 @@ namespace TV_Player.MAUI
|
|||||||
public ProgramViewModel(GroupInfo groupInfo)
|
public ProgramViewModel(GroupInfo groupInfo)
|
||||||
{
|
{
|
||||||
ItemSelectedCommand = new Command(OnItemSelected);
|
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()
|
private void OnItemSelected()
|
||||||
@@ -33,6 +34,8 @@ namespace TV_Player.MAUI
|
|||||||
};
|
};
|
||||||
// Navigate to the OtherPage
|
// Navigate to the OtherPage
|
||||||
navigation.PushAsync(playerPage);
|
navigation.PushAsync(playerPage);
|
||||||
|
|
||||||
|
_programSubscriber.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,36 +4,42 @@ namespace TV_Player.MAUI
|
|||||||
{
|
{
|
||||||
public class ProgramsData
|
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<M3UInfo>> programsSubject = new ReplaySubject<List<M3UInfo>>();
|
||||||
private readonly ReplaySubject<List<GroupInfo>> groupsSubject = new ReplaySubject<List<GroupInfo>>();
|
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<M3UInfo>> AllPrograms => programsSubject;
|
||||||
public IObservable<List<GroupInfo>> GroupsInformation => groupsSubject;
|
public IObservable<List<GroupInfo>> GroupsInformation => groupsSubject;
|
||||||
|
|
||||||
private ProgramsData()
|
public IObservable<List<ProgramGuide>> ProgramGuideInfo => programGuideSubject;
|
||||||
{
|
public ProgramsData()
|
||||||
_=Initialize();
|
{
|
||||||
}
|
}
|
||||||
private async Task Initialize()
|
|
||||||
|
private async Task GetPrograms(string m3uLink)
|
||||||
{
|
{
|
||||||
string m3uLink = "http://pl.da-tv.vip/a71e77fa/835b3216/tv.m3u";
|
//string m3uLink = "http://pl.da-tv.vip/a71e77fa/835b3216/tv.m3u";
|
||||||
var programs = await M3UParser.DownloadM3UFromWebAsync(m3uLink);
|
var result = await M3UParser.DownloadM3UFromWebAsync(m3uLink);
|
||||||
|
|
||||||
|
programsSubject.OnNext(result.programList);
|
||||||
|
|
||||||
programsSubject.OnNext(programs);
|
var groupping = result.programList.GroupBy(item => item.GroupTitle)
|
||||||
|
|
||||||
var groupping = programs.GroupBy(item => item.GroupTitle)
|
|
||||||
.Select(group => new GroupInfo() { Name = group.Key, Count = group.Count() })
|
.Select(group => new GroupInfo() { Name = group.Key, Count = group.Count() })
|
||||||
.ToList();
|
.ToList();
|
||||||
groupsSubject.OnNext(groupping);
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user