- Updated NuGet packs
- Added quality switcher to livestreams - Fixed SettingsStorage cast - Completed ManifestGenerator (but still doesn't work) - Refactored and redesigned player - Created test project
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
@@ -0,0 +1,172 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||||
|
<ProjectGuid>{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}</ProjectGuid>
|
||||||
|
<OutputType>AppContainerExe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>FoxTube.Tests</RootNamespace>
|
||||||
|
<AssemblyName>FoxTube.Tests</AssemblyName>
|
||||||
|
<DefaultLanguage>en-US</DefaultLanguage>
|
||||||
|
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||||
|
<TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion>
|
||||||
|
<TargetPlatformMinVersion>10.0.17134.0</TargetPlatformMinVersion>
|
||||||
|
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<PackageCertificateKeyFile>FoxTube.Tests_TemporaryKey.pfx</PackageCertificateKeyFile>
|
||||||
|
<UnitTestPlatformVersion Condition="'$(UnitTestPlatformVersion)' == ''">$(VisualStudioVersion)</UnitTestPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||||
|
<OutputPath>bin\x86\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>bin\ARM\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>ARM</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
|
||||||
|
<OutputPath>bin\ARM\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>ARM</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM64'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>bin\ARM64\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>ARM64</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM64'">
|
||||||
|
<OutputPath>bin\ARM64\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>ARM64</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||||
|
<OutputPath>bin\x64\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<NoWarn>;2008</NoWarn>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<SDKReference Include="TestPlatform.Universal, Version=$(UnitTestPlatformVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="UnitTestApp.xaml.cs">
|
||||||
|
<DependentUpon>UnitTestApp.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="UnitTest.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ApplicationDefinition Include="UnitTestApp.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</ApplicationDefinition>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AppxManifest Include="Package.appxmanifest">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</AppxManifest>
|
||||||
|
<None Include="FoxTube.Tests_TemporaryKey.pfx" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Properties\UnitTestApp.rd.xml" />
|
||||||
|
<Content Include="Assets\LockScreenLogo.scale-200.png" />
|
||||||
|
<Content Include="Assets\SplashScreen.scale-200.png" />
|
||||||
|
<Content Include="Assets\Square150x150Logo.scale-200.png" />
|
||||||
|
<Content Include="Assets\Square44x44Logo.scale-200.png" />
|
||||||
|
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||||
|
<Content Include="Assets\StoreLogo.png" />
|
||||||
|
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
|
||||||
|
<Version>6.2.8</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="MSTest.TestAdapter">
|
||||||
|
<Version>1.4.0</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="MSTest.TestFramework">
|
||||||
|
<Version>1.4.0</Version>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
||||||
|
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Package
|
||||||
|
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||||
|
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||||
|
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||||
|
IgnorableNamespaces="uap mp">
|
||||||
|
|
||||||
|
<Identity Name="d50f8eba-0ea7-439d-850c-b1882d571731"
|
||||||
|
Publisher="CN=XFox"
|
||||||
|
Version="1.0.0.0" />
|
||||||
|
|
||||||
|
<mp:PhoneIdentity PhoneProductId="d50f8eba-0ea7-439d-850c-b1882d571731" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||||
|
|
||||||
|
<Properties>
|
||||||
|
<DisplayName>FoxTube.Tests</DisplayName>
|
||||||
|
<PublisherDisplayName>XFox</PublisherDisplayName>
|
||||||
|
<Logo>Assets\StoreLogo.png</Logo>
|
||||||
|
</Properties>
|
||||||
|
|
||||||
|
<Dependencies>
|
||||||
|
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
|
||||||
|
</Dependencies>
|
||||||
|
|
||||||
|
<Resources>
|
||||||
|
<Resource Language="x-generate" />
|
||||||
|
</Resources>
|
||||||
|
<Applications>
|
||||||
|
<Application Id="vstest.executionengine.universal.App"
|
||||||
|
Executable="$targetnametoken$.exe"
|
||||||
|
EntryPoint="FoxTube.Tests.App">
|
||||||
|
<uap:VisualElements
|
||||||
|
DisplayName="FoxTube.Tests"
|
||||||
|
Square150x150Logo="Assets\Square150x150Logo.png"
|
||||||
|
Square44x44Logo="Assets\Square44x44Logo.png"
|
||||||
|
Description="FoxTube.Tests"
|
||||||
|
BackgroundColor="transparent">
|
||||||
|
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png"/>
|
||||||
|
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
||||||
|
</uap:VisualElements>
|
||||||
|
</Application>
|
||||||
|
</Applications>
|
||||||
|
<Capabilities>
|
||||||
|
<Capability Name="internetClientServer" />
|
||||||
|
<Capability Name="privateNetworkClientServer" />
|
||||||
|
</Capabilities>
|
||||||
|
</Package>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
[assembly: AssemblyTitle("FoxTube.Tests")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("FoxTube.Tests")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
[assembly: AssemblyMetadata("TargetPlatform","UAP")]
|
||||||
|
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<!--
|
||||||
|
This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
|
||||||
|
developers. However, you can modify these parameters to modify the behavior of the .NET Native
|
||||||
|
optimizer.
|
||||||
|
|
||||||
|
Runtime Directives are documented at https://go.microsoft.com/fwlink/?LinkID=391919
|
||||||
|
|
||||||
|
To fully enable reflection for App1.MyClass and all of its public/private members
|
||||||
|
<Type Name="App1.MyClass" Dynamic="Required All"/>
|
||||||
|
|
||||||
|
To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
|
||||||
|
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
|
||||||
|
|
||||||
|
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
|
||||||
|
<Namespace Name="DataClasses.ViewModels" Serialize="All" />
|
||||||
|
-->
|
||||||
|
|
||||||
|
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
|
||||||
|
<Application>
|
||||||
|
<!--
|
||||||
|
An Assembly element with Name="*Application*" applies to all assemblies in
|
||||||
|
the application package. The asterisks are not wildcards.
|
||||||
|
-->
|
||||||
|
<Assembly Name="*Application*" Dynamic="Required All" />
|
||||||
|
<!-- Add your application specific runtime directives here. -->
|
||||||
|
|
||||||
|
|
||||||
|
</Application>
|
||||||
|
</Directives>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
|
||||||
|
namespace FoxTube.Tests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class UnitTest1
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void TestMethod1()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<Application
|
||||||
|
x:Class="FoxTube.Tests.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="using:FoxTube.Tests">
|
||||||
|
|
||||||
|
</Application>
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices.WindowsRuntime;
|
||||||
|
using Windows.ApplicationModel;
|
||||||
|
using Windows.ApplicationModel.Activation;
|
||||||
|
using Windows.Foundation;
|
||||||
|
using Windows.Foundation.Collections;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
using Windows.UI.Xaml.Controls.Primitives;
|
||||||
|
using Windows.UI.Xaml.Data;
|
||||||
|
using Windows.UI.Xaml.Input;
|
||||||
|
using Windows.UI.Xaml.Media;
|
||||||
|
using Windows.UI.Xaml.Navigation;
|
||||||
|
|
||||||
|
namespace FoxTube.Tests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides application-specific behavior to supplement the default Application class.
|
||||||
|
/// </summary>
|
||||||
|
sealed partial class App : Application
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 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().
|
||||||
|
/// </summary>
|
||||||
|
public App()
|
||||||
|
{
|
||||||
|
this.InitializeComponent();
|
||||||
|
this.Suspending += OnSuspending;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when the application is launched normally by the end user. Other entry points
|
||||||
|
/// will be used such as when the application is launched to open a specific file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">Details about the launch request and process.</param>
|
||||||
|
protected override void OnLaunched(LaunchActivatedEventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
if (System.Diagnostics.Debugger.IsAttached)
|
||||||
|
{
|
||||||
|
this.DebugSettings.EnableFrameRateCounter = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Frame rootFrame = Window.Current.Content as Frame;
|
||||||
|
|
||||||
|
// Do not repeat app initialization when the Window already has content,
|
||||||
|
// just ensure that the window is active
|
||||||
|
if (rootFrame == null)
|
||||||
|
{
|
||||||
|
// Create a Frame to act as the navigation context and navigate to the first page
|
||||||
|
rootFrame = new Frame();
|
||||||
|
|
||||||
|
rootFrame.NavigationFailed += OnNavigationFailed;
|
||||||
|
|
||||||
|
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
|
||||||
|
{
|
||||||
|
//TODO: Load state from previously suspended application
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place the frame in the current Window
|
||||||
|
Window.Current.Content = rootFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.CreateDefaultUI();
|
||||||
|
|
||||||
|
// Ensure the current window is active
|
||||||
|
Window.Current.Activate();
|
||||||
|
|
||||||
|
Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.Run(e.Arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when Navigation to a certain page fails
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The Frame which failed navigation</param>
|
||||||
|
/// <param name="e">Details about the navigation failure</param>
|
||||||
|
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
|
||||||
|
{
|
||||||
|
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when application execution is being suspended. Application state is saved
|
||||||
|
/// without knowing whether the application will be terminated or resumed with the contents
|
||||||
|
/// of memory still intact.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The source of the suspend request.</param>
|
||||||
|
/// <param name="e">Details about the suspend request.</param>
|
||||||
|
private void OnSuspending(object sender, SuspendingEventArgs e)
|
||||||
|
{
|
||||||
|
var deferral = e.SuspendingOperation.GetDeferral();
|
||||||
|
//TODO: Save application state and stop any background activity
|
||||||
|
deferral.Complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,24 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 15.0.27428.1
|
VisualStudioVersion = 16.0.28803.352
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoxTube", "FoxTube\FoxTube.csproj", "{2597B816-7316-4D20-BA6C-D78001E89C1A}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoxTube", "FoxTube\FoxTube.csproj", "{2597B816-7316-4D20-BA6C-D78001E89C1A}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoxTube.Background", "FoxTube.Background\FoxTube.Background.csproj", "{FC9128D7-E3AA-48ED-8641-629794B88B28}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoxTube.Background", "FoxTube.Background\FoxTube.Background.csproj", "{FC9128D7-E3AA-48ED-8641-629794B88B28}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoxTube.Tests", "FoxTube.Tests\FoxTube.Tests.csproj", "{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
Debug|ARM = Debug|ARM
|
Debug|ARM = Debug|ARM
|
||||||
|
Debug|ARM64 = Debug|ARM64
|
||||||
Debug|x64 = Debug|x64
|
Debug|x64 = Debug|x64
|
||||||
Debug|x86 = Debug|x86
|
Debug|x86 = Debug|x86
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
Release|ARM = Release|ARM
|
Release|ARM = Release|ARM
|
||||||
|
Release|ARM64 = Release|ARM64
|
||||||
Release|x64 = Release|x64
|
Release|x64 = Release|x64
|
||||||
Release|x86 = Release|x86
|
Release|x86 = Release|x86
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
@@ -23,6 +27,7 @@ Global
|
|||||||
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Debug|ARM.ActiveCfg = Debug|ARM
|
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Debug|ARM.ActiveCfg = Debug|ARM
|
||||||
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Debug|ARM.Build.0 = Debug|ARM
|
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Debug|ARM.Build.0 = Debug|ARM
|
||||||
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Debug|ARM.Deploy.0 = Debug|ARM
|
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Debug|ARM.Deploy.0 = Debug|ARM
|
||||||
|
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Debug|ARM64.ActiveCfg = Debug|x86
|
||||||
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Debug|x64.ActiveCfg = Debug|x64
|
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Debug|x64.Build.0 = Debug|x64
|
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Debug|x64.Build.0 = Debug|x64
|
||||||
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Debug|x64.Deploy.0 = Debug|x64
|
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Debug|x64.Deploy.0 = Debug|x64
|
||||||
@@ -33,6 +38,7 @@ Global
|
|||||||
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Release|ARM.ActiveCfg = Release|ARM
|
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Release|ARM.ActiveCfg = Release|ARM
|
||||||
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Release|ARM.Build.0 = Release|ARM
|
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Release|ARM.Build.0 = Release|ARM
|
||||||
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Release|ARM.Deploy.0 = Release|ARM
|
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Release|ARM.Deploy.0 = Release|ARM
|
||||||
|
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Release|ARM64.ActiveCfg = Release|x86
|
||||||
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Release|x64.ActiveCfg = Release|x64
|
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Release|x64.ActiveCfg = Release|x64
|
||||||
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Release|x64.Build.0 = Release|x64
|
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Release|x64.Build.0 = Release|x64
|
||||||
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Release|x64.Deploy.0 = Release|x64
|
{2597B816-7316-4D20-BA6C-D78001E89C1A}.Release|x64.Deploy.0 = Release|x64
|
||||||
@@ -43,6 +49,8 @@ Global
|
|||||||
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Debug|ARM.ActiveCfg = Debug|ARM
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Debug|ARM.ActiveCfg = Debug|ARM
|
||||||
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Debug|ARM.Build.0 = Debug|ARM
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Debug|ARM.Build.0 = Debug|ARM
|
||||||
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||||
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||||
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Debug|x64.ActiveCfg = Debug|x64
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Debug|x64.Build.0 = Debug|x64
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Debug|x64.Build.0 = Debug|x64
|
||||||
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Debug|x86.ActiveCfg = Debug|x86
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
@@ -51,10 +59,38 @@ Global
|
|||||||
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|Any CPU.Build.0 = Release|Any CPU
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|ARM.ActiveCfg = Release|ARM
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|ARM.ActiveCfg = Release|ARM
|
||||||
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|ARM.Build.0 = Release|ARM
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|ARM.Build.0 = Release|ARM
|
||||||
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||||
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|ARM64.Build.0 = Release|Any CPU
|
||||||
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|x64.ActiveCfg = Release|x64
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|x64.ActiveCfg = Release|x64
|
||||||
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|x64.Build.0 = Release|x64
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|x64.Build.0 = Release|x64
|
||||||
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|x86.ActiveCfg = Release|x86
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|x86.ActiveCfg = Release|x86
|
||||||
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|x86.Build.0 = Release|x86
|
{FC9128D7-E3AA-48ED-8641-629794B88B28}.Release|x86.Build.0 = Release|x86
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Debug|ARM.ActiveCfg = Debug|ARM
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Debug|ARM.Build.0 = Debug|ARM
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Debug|ARM.Deploy.0 = Debug|ARM
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Debug|x64.Deploy.0 = Debug|x64
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Debug|x86.Deploy.0 = Debug|x86
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|Any CPU.ActiveCfg = Release|x86
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|ARM.ActiveCfg = Release|ARM
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|ARM.Build.0 = Release|ARM
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|ARM.Deploy.0 = Release|ARM
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|ARM64.Build.0 = Release|ARM64
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|ARM64.Deploy.0 = Release|ARM64
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|x64.Build.0 = Release|x64
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|x64.Deploy.0 = Release|x64
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|x86.Build.0 = Release|x86
|
||||||
|
{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|x86.Deploy.0 = Release|x86
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
@@ -267,6 +267,7 @@ namespace FoxTube
|
|||||||
|
|
||||||
SettingsStorage.SaveData();
|
SettingsStorage.SaveData();
|
||||||
DownloadAgent.QuitPrompt();
|
DownloadAgent.QuitPrompt();
|
||||||
|
Controls.Player.ManifestGenerator.ClearRoaming();
|
||||||
deferral.Complete();
|
deferral.Complete();
|
||||||
Analytics.TrackEvent("Session terminated");
|
Analytics.TrackEvent("Session terminated");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
- FoxTube pro price is now displayed in menu
|
- FoxTube pro price is now displayed in menu
|
||||||
- Fixed crashes on opening links which don't contain http(s) prefix
|
- Fixed crashes on opening links which don't contain http(s) prefix
|
||||||
- Fixed backward navigation with minimized video
|
- Fixed backward navigation with minimized video
|
||||||
|
- Player re-design
|
||||||
|
- Added quality selector to live streams playback
|
||||||
</en-US>
|
</en-US>
|
||||||
<ru-RU>### Что нового:
|
<ru-RU>### Что нового:
|
||||||
- Исправлена проблема получения истории, "Посмотреть позже" и рекомендаций
|
- Исправлена проблема получения истории, "Посмотреть позже" и рекомендаций
|
||||||
@@ -37,6 +39,8 @@
|
|||||||
- Теперь на кнопке отключения рекламы отображается текущая цена
|
- Теперь на кнопке отключения рекламы отображается текущая цена
|
||||||
- Исправлены вылеты при попытке открыть ссылку не содержащую http(s) префикс
|
- Исправлены вылеты при попытке открыть ссылку не содержащую http(s) префикс
|
||||||
- Исправлена обратная навигация при уменьшенном видео
|
- Исправлена обратная навигация при уменьшенном видео
|
||||||
|
- Редизайн плеера
|
||||||
|
- Добавлено меню выбора качества для прямых эфиров
|
||||||
</ru-RU>
|
</ru-RU>
|
||||||
</content>
|
</content>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
@@ -1,26 +1,42 @@
|
|||||||
using System;
|
using AngleSharp.Dom.Html;
|
||||||
using System.Threading.Tasks;
|
using AngleSharp.Parser.Html;
|
||||||
using YoutubeExplode.Models.MediaStreams;
|
|
||||||
using Windows.Storage;
|
|
||||||
using Google.Apis.YouTube.v3.Data;
|
using Google.Apis.YouTube.v3.Data;
|
||||||
using System.Xml;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Web;
|
||||||
|
using System.Xml;
|
||||||
|
using Windows.Storage;
|
||||||
|
using YoutubeExplode.Models.MediaStreams;
|
||||||
|
|
||||||
namespace FoxTube.Controls.Player
|
namespace FoxTube.Controls.Player
|
||||||
{
|
{
|
||||||
public static class ManifestGenerator
|
public static class ManifestGenerator
|
||||||
{
|
{
|
||||||
static StorageFolder roaming = ApplicationData.Current.RoamingFolder;
|
static readonly StorageFolder roaming = ApplicationData.Current.RoamingFolder;
|
||||||
public static async Task<Uri> GetManifest(Video meta, VideoStreamInfo requestedQuality, MediaStreamInfoSet list)
|
public static async Task<Uri> GetManifest(Video meta, VideoStreamInfo requestedQuality, MediaStreamInfoSet list)
|
||||||
{
|
{
|
||||||
StorageFile manifest = await roaming.CreateFileAsync("manifest.mpd", CreationCollisionOption.ReplaceExisting);
|
StorageFile manifest;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
manifest = await roaming.CreateFileAsync("manifest.mpd", CreationCollisionOption.ReplaceExisting);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
manifest = await roaming.CreateFileAsync("manifest.mpd", CreationCollisionOption.GenerateUniqueName);
|
||||||
|
}
|
||||||
|
|
||||||
XmlDocument doc = new XmlDocument();
|
XmlDocument doc = new XmlDocument();
|
||||||
|
|
||||||
XmlElement mpd = doc.CreateElement("MPD");
|
XmlElement mpd = doc.CreateElement("MPD");
|
||||||
mpd.SetAttribute("mediaPresentationDuration", meta.ContentDetails.Duration);
|
mpd.SetAttribute("mediaPresentationDuration", meta.ContentDetails.Duration);
|
||||||
|
mpd.SetAttribute("minBufferTime", "PT2S");
|
||||||
|
|
||||||
XmlElement period = doc.CreateElement("Period");
|
XmlElement period = doc.CreateElement("Period");
|
||||||
period.SetAttribute("duration", meta.ContentDetails.Duration);
|
period.SetAttribute("duration", meta.ContentDetails.Duration);
|
||||||
@@ -31,7 +47,29 @@ namespace FoxTube.Controls.Player
|
|||||||
videoMeta.SetAttribute("contentType", "video");
|
videoMeta.SetAttribute("contentType", "video");
|
||||||
videoSet.AppendChild(videoMeta);
|
videoSet.AppendChild(videoMeta);
|
||||||
|
|
||||||
AppendVideoSet(doc, videoSet, list.Video);
|
StreamInfo streamInfo = await GetInfoAsync(meta, requestedQuality, list);
|
||||||
|
|
||||||
|
XmlElement representation = doc.CreateElement("Representation");
|
||||||
|
representation.SetAttribute("bandwidth", GetBandwidth(requestedQuality.VideoQuality));
|
||||||
|
representation.SetAttribute("height", requestedQuality.Resolution.Height.ToString());
|
||||||
|
representation.SetAttribute("width", requestedQuality.Resolution.Width.ToString());
|
||||||
|
representation.SetAttribute("id", "1");
|
||||||
|
representation.SetAttribute("codecs", requestedQuality.VideoEncoding.ToString());
|
||||||
|
representation.SetAttribute("mimeType", $"video/{requestedQuality.Container.GetFileExtension()}");
|
||||||
|
|
||||||
|
XmlElement baseUrl = doc.CreateElement("BaseURL");
|
||||||
|
baseUrl.InnerText = requestedQuality.Url;
|
||||||
|
representation.AppendChild(baseUrl);
|
||||||
|
|
||||||
|
XmlElement segmentBase = doc.CreateElement("SegmentBase");
|
||||||
|
segmentBase.SetAttribute("indexRange", streamInfo.Video.IndexRange);
|
||||||
|
representation.AppendChild(segmentBase);
|
||||||
|
|
||||||
|
XmlElement initialization = doc.CreateElement("Initialization");
|
||||||
|
initialization.SetAttribute("range", streamInfo.Video.InitRange);
|
||||||
|
segmentBase.AppendChild(initialization);
|
||||||
|
|
||||||
|
videoSet.AppendChild(representation);
|
||||||
|
|
||||||
XmlElement audioSet = doc.CreateElement("AdaptationSet");
|
XmlElement audioSet = doc.CreateElement("AdaptationSet");
|
||||||
XmlElement audioMeta = doc.CreateElement("ContentComponent");
|
XmlElement audioMeta = doc.CreateElement("ContentComponent");
|
||||||
@@ -39,15 +77,26 @@ namespace FoxTube.Controls.Player
|
|||||||
audioSet.AppendChild(audioMeta);
|
audioSet.AppendChild(audioMeta);
|
||||||
|
|
||||||
XmlElement audio = doc.CreateElement("Representation");
|
XmlElement audio = doc.CreateElement("Representation");
|
||||||
audio.SetAttribute("bandwidth", "100000");
|
audio.SetAttribute("bandwidth", "200000");
|
||||||
audio.SetAttribute("id", (list.Video.Count + 1).ToString());
|
audio.SetAttribute("id", "2");
|
||||||
audio.SetAttribute("mimeType", $"audio/{list.Audio.First().Container.GetFileExtension()}");
|
audio.SetAttribute("sampleRate", streamInfo.Audio.SampleRate);
|
||||||
|
audio.SetAttribute("numChannels", streamInfo.Audio.ChannelsCount);
|
||||||
|
audio.SetAttribute("codecs", list.Audio.First(i => i.Container.GetFileExtension() == "webm").AudioEncoding.ToString());
|
||||||
|
audio.SetAttribute("mimeType", $"audio/{list.Audio.First(i => i.Container.GetFileExtension() == "webm").Container.GetFileExtension()}");
|
||||||
|
audioSet.AppendChild(audio);
|
||||||
|
|
||||||
XmlElement audioUrl = doc.CreateElement("BaseURL");
|
XmlElement audioUrl = doc.CreateElement("BaseURL");
|
||||||
audioUrl.InnerText = list.Audio.First().Url;
|
audioUrl.InnerText = list.Audio.First(i => i.Container.GetFileExtension() == "webm").Url;
|
||||||
|
|
||||||
audio.AppendChild(audioUrl);
|
audio.AppendChild(audioUrl);
|
||||||
audioSet.AppendChild(audio);
|
|
||||||
|
XmlElement audioSegmentBase = doc.CreateElement("SegmentBase");
|
||||||
|
audioSegmentBase.SetAttribute("indexRange", streamInfo.Audio.IndexRange);
|
||||||
|
audioSegmentBase.SetAttribute("indexRangeExact", "true");
|
||||||
|
audio.AppendChild(audioSegmentBase);
|
||||||
|
|
||||||
|
XmlElement audioInit = doc.CreateElement("Initialization");
|
||||||
|
audioInit.SetAttribute("range", streamInfo.Audio.InitRange);
|
||||||
|
audioSegmentBase.AppendChild(audioInit);
|
||||||
|
|
||||||
doc.AppendChild(mpd);
|
doc.AppendChild(mpd);
|
||||||
mpd.AppendChild(period);
|
mpd.AppendChild(period);
|
||||||
@@ -56,10 +105,69 @@ namespace FoxTube.Controls.Player
|
|||||||
|
|
||||||
doc.Save(await manifest.OpenStreamForWriteAsync());
|
doc.Save(await manifest.OpenStreamForWriteAsync());
|
||||||
|
|
||||||
return "ms-appdata:///roaming/manifest.mpd".ToUri();
|
//TODO: Fix this shit. It doesn't work
|
||||||
|
return $"ms-appdata:///roaming/{manifest.Name}".ToUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AppendVideoSet(XmlDocument doc, XmlElement root, IReadOnlyList<VideoStreamInfo> list)
|
private static async Task<StreamInfo> GetInfoAsync(Video info, VideoStreamInfo requestedQuality, MediaStreamInfoSet list)
|
||||||
|
{
|
||||||
|
HttpClient http = new HttpClient();
|
||||||
|
string response = HttpUtility.HtmlDecode(await http.GetStringAsync($"https://youtube.com/embed/{info.Id}?disable_polymer=true&hl=en"));
|
||||||
|
IHtmlDocument videoEmbedPageHtml = new HtmlParser().Parse(response);
|
||||||
|
|
||||||
|
string playerConfigRaw = Regex.Match(videoEmbedPageHtml.Source.Text,
|
||||||
|
@"yt\.setConfig\({'PLAYER_CONFIG': (?<Json>\{[^\{\}]*(((?<Open>\{)[^\{\}]*)+((?<Close-Open>\})[^\{\}]*)+)*(?(Open)(?!))\})")
|
||||||
|
.Groups["Json"].Value;
|
||||||
|
JToken playerConfigJson = JToken.Parse(playerConfigRaw);
|
||||||
|
string sts = playerConfigJson.SelectToken("sts").Value<string>();
|
||||||
|
|
||||||
|
string eurl = WebUtility.UrlEncode($"https://youtube.googleapis.com/v/{info.Id}");
|
||||||
|
string url = $"https://youtube.com/get_video_info?video_id={info.Id}&el=embedded&sts={sts}&eurl={eurl}&hl=en";
|
||||||
|
string raw = await http.GetStringAsync(url);
|
||||||
|
|
||||||
|
Dictionary<string, string> videoInfoDic = SplitQuery(raw);
|
||||||
|
|
||||||
|
StreamInfo si = new StreamInfo();
|
||||||
|
|
||||||
|
List<Dictionary<string, string>> adaptiveStreamInfosUrl = videoInfoDic.GetValueOrDefault("adaptive_fmts").Split(',').Select(SplitQuery).ToList();
|
||||||
|
Dictionary<string, string> video = adaptiveStreamInfosUrl.Find(i => i["quality_label"] == requestedQuality.VideoQualityLabel && i["type"].Contains(requestedQuality.Container.GetFileExtension()));
|
||||||
|
Dictionary<string, string> audio = adaptiveStreamInfosUrl.Find(i => i.ContainsKey("audio_sample_rate") && i["type"].Contains("webm"));
|
||||||
|
|
||||||
|
si.Video.IndexRange = video["index"];
|
||||||
|
si.Audio.ChannelsCount = audio["audio_channels"];
|
||||||
|
si.Audio.IndexRange = audio["index"];
|
||||||
|
si.Audio.SampleRate = audio["audio_sample_rate"];
|
||||||
|
|
||||||
|
return si;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Dictionary<string, string> SplitQuery(string query)
|
||||||
|
{
|
||||||
|
Dictionary<string, string> dic = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
string[] paramsEncoded = query.TrimStart('?').Split("&");
|
||||||
|
foreach (string paramEncoded in paramsEncoded)
|
||||||
|
{
|
||||||
|
string param = WebUtility.UrlDecode(paramEncoded);
|
||||||
|
|
||||||
|
// Look for the equals sign
|
||||||
|
int equalsPos = param.IndexOf('=');
|
||||||
|
if (equalsPos <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Get the key and value
|
||||||
|
string key = param.Substring(0, equalsPos);
|
||||||
|
string value = equalsPos < param.Length
|
||||||
|
? param.Substring(equalsPos + 1)
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
// Add to dictionary
|
||||||
|
dic[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dic;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AppendVideoSet(XmlDocument doc, XmlElement root, List<VideoStreamInfo> list)
|
||||||
{
|
{
|
||||||
for (int k = 0; k < list.Count; k++)
|
for (int k = 0; k < list.Count; k++)
|
||||||
{
|
{
|
||||||
@@ -114,5 +222,79 @@ namespace FoxTube.Controls.Player
|
|||||||
return $"100000";
|
return $"100000";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<List<StreamQuality>> ResolveLiveSteream(string url)
|
||||||
|
{
|
||||||
|
List<StreamQuality> list = new List<StreamQuality>();
|
||||||
|
string playlistRaw = await new HttpClient().GetStringAsync(url);
|
||||||
|
|
||||||
|
List<string> streamsRaw = playlistRaw.Split("#EXT-X-STREAM-INF:").ToList();
|
||||||
|
streamsRaw.RemoveAt(0);
|
||||||
|
List<Dictionary<string, string>> streams = new List<Dictionary<string, string>>();
|
||||||
|
foreach (string i in streamsRaw)
|
||||||
|
{
|
||||||
|
Dictionary<string, string> item = new Dictionary<string, string>();
|
||||||
|
string[] par = i.Split('\n');
|
||||||
|
item.Add("URL", par[1]);
|
||||||
|
par = par[0].Split(',');
|
||||||
|
foreach (string k in par)
|
||||||
|
{
|
||||||
|
string[] pair = k.Split('=');
|
||||||
|
if (pair.Length < 2)
|
||||||
|
continue;
|
||||||
|
item[pair[0]] = pair[1];
|
||||||
|
}
|
||||||
|
streams.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var i in streams)
|
||||||
|
{
|
||||||
|
StreamQuality item = new StreamQuality();
|
||||||
|
item.Resolution = $"{i["RESOLUTION"].Split('x')[1]}p";
|
||||||
|
item.Url = i["URL"].ToUri();
|
||||||
|
list.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
list.Add(new StreamQuality
|
||||||
|
{
|
||||||
|
Resolution = "Auto",
|
||||||
|
Url = url.ToUri()
|
||||||
|
});
|
||||||
|
list.Reverse();
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async void ClearRoaming()
|
||||||
|
{
|
||||||
|
IReadOnlyList<StorageFile> items = await roaming.GetFilesAsync();
|
||||||
|
foreach (StorageFile f in items)
|
||||||
|
await f.DeleteAsync(StorageDeleteOption.PermanentDelete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StreamInfo
|
||||||
|
{
|
||||||
|
public class VideoInfo
|
||||||
|
{
|
||||||
|
public string IndexRange { get; set; }
|
||||||
|
public string InitRange => $"0-{int.Parse(IndexRange.Split('-')[0]) - 1}";
|
||||||
|
}
|
||||||
|
public class AudioInfo
|
||||||
|
{
|
||||||
|
public string IndexRange { get; set; }
|
||||||
|
public string InitRange => $"0-{int.Parse(IndexRange.Split('-')[0]) - 1}";
|
||||||
|
public string SampleRate { get; set; }
|
||||||
|
public string ChannelsCount { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public VideoInfo Video { get; } = new VideoInfo();
|
||||||
|
public AudioInfo Audio { get; } = new AudioInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StreamQuality
|
||||||
|
{
|
||||||
|
public Uri Url { get; set; }
|
||||||
|
public string Resolution { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ namespace FoxTube
|
|||||||
|
|
||||||
private static void Save()
|
private static void Save()
|
||||||
{
|
{
|
||||||
ApplicationData.Current.RoamingSettings.Values[$"history-{SecretsVault.AccountId}"] = JsonConvert.SerializeObject(Items);
|
try { ApplicationData.Current.RoamingSettings.Values[$"history-{SecretsVault.AccountId}"] = JsonConvert.SerializeObject(Items); }
|
||||||
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Load()
|
public static void Load()
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ namespace FoxTube
|
|||||||
{
|
{
|
||||||
if (storage.Values["mature"] == null)
|
if (storage.Values["mature"] == null)
|
||||||
{
|
{
|
||||||
storage.Values["mature"] = MatureState.Blocked;
|
storage.Values["mature"] = (int)MatureState.Blocked;
|
||||||
return MatureState.Blocked;
|
return MatureState.Blocked;
|
||||||
}
|
}
|
||||||
else return (MatureState)storage.Values["mature"];
|
else return (MatureState)storage.Values["mature"];
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ namespace FoxTube.Controls
|
|||||||
else
|
else
|
||||||
rating.Text = comment.Snippet.TopLevelComment.Snippet.LikeCount.HasValue ? comment.Snippet.TopLevelComment.Snippet.LikeCount.ToString() : "";
|
rating.Text = comment.Snippet.TopLevelComment.Snippet.LikeCount.HasValue ? comment.Snippet.TopLevelComment.Snippet.LikeCount.ToString() : "";
|
||||||
|
|
||||||
|
if(item.Snippet.AuthorChannelId != null)
|
||||||
|
{
|
||||||
if (item.Snippet.AuthorChannelId.ToString().Split('"')[3] == SecretsVault.AccountId)
|
if (item.Snippet.AuthorChannelId.ToString().Split('"')[3] == SecretsVault.AccountId)
|
||||||
{
|
{
|
||||||
(specialAuthor.Child as TextBlock).Text = comment.Snippet.TopLevelComment.Snippet.AuthorDisplayName;
|
(specialAuthor.Child as TextBlock).Text = comment.Snippet.TopLevelComment.Snippet.AuthorDisplayName;
|
||||||
@@ -65,7 +67,7 @@ namespace FoxTube.Controls
|
|||||||
specialAuthor.Visibility = Visibility.Visible;
|
specialAuthor.Visibility = Visibility.Visible;
|
||||||
author.Visibility = Visibility.Collapsed;
|
author.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
author.Text = comment.Snippet.TopLevelComment.Snippet.AuthorDisplayName;
|
author.Text = comment.Snippet.TopLevelComment.Snippet.AuthorDisplayName;
|
||||||
|
|
||||||
meta.Text = string.Format("{0} {1}", Methods.GetAgo(comment.Snippet.TopLevelComment.Snippet.PublishedAt.Value), comment.Snippet.TopLevelComment.Snippet.UpdatedAt != comment.Snippet.TopLevelComment.Snippet.PublishedAt ? resources.GetString("/CommentsPage/edited") : "");
|
meta.Text = string.Format("{0} {1}", Methods.GetAgo(comment.Snippet.TopLevelComment.Snippet.PublishedAt.Value), comment.Snippet.TopLevelComment.Snippet.UpdatedAt != comment.Snippet.TopLevelComment.Snippet.PublishedAt ? resources.GetString("/CommentsPage/edited") : "");
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ namespace FoxTube.Controls
|
|||||||
set => text.FontSize = value;
|
set => text.FontSize = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MediaPlayer Player { get; set; }
|
public bool IsActive => track != null;
|
||||||
|
|
||||||
|
public MediaElement Player { get; set; }
|
||||||
|
|
||||||
DispatcherTimer timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(10) };
|
DispatcherTimer timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(10) };
|
||||||
ClosedCaption currentCaption = null;
|
ClosedCaption currentCaption = null;
|
||||||
@@ -32,7 +34,7 @@ namespace FoxTube.Controls
|
|||||||
|
|
||||||
private void UpdateCaption(object sender, object e)
|
private void UpdateCaption(object sender, object e)
|
||||||
{
|
{
|
||||||
currentCaption = track.Captions.Find(i => i.Offset <= Player.PlaybackSession.Position && i.Offset + i.Duration > Player.PlaybackSession.Position);
|
currentCaption = track.Captions.Find(i => i.Offset <= Player.Position && i.Offset + i.Duration > Player.Position);
|
||||||
|
|
||||||
if (currentCaption != null)
|
if (currentCaption != null)
|
||||||
text.Text = currentCaption.Text;
|
text.Text = currentCaption.Text;
|
||||||
@@ -51,10 +53,22 @@ namespace FoxTube.Controls
|
|||||||
|
|
||||||
public void Close()
|
public void Close()
|
||||||
{
|
{
|
||||||
|
timer.Stop();
|
||||||
track = null;
|
track = null;
|
||||||
currentCaption = null;
|
currentCaption = null;
|
||||||
Visibility = Visibility.Collapsed;
|
Visibility = Visibility.Collapsed;
|
||||||
timer.Stop();
|
}
|
||||||
|
|
||||||
|
public void Minimize()
|
||||||
|
{
|
||||||
|
Margin = new Thickness(0, 0, 0, 20);
|
||||||
|
text.FontSize = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Maximize()
|
||||||
|
{
|
||||||
|
Margin = new Thickness(0, 0, 0, 55);
|
||||||
|
text.FontSize = 24;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,111 @@
|
|||||||
using FoxTube.Controls;
|
using FoxTube.Controls;
|
||||||
using FoxTube.Controls.Adverts;
|
using FoxTube.Controls.Adverts;
|
||||||
|
using FoxTube.Controls.Player;
|
||||||
|
using Google.Apis.YouTube.v3.Data;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Windows.ApplicationModel.Resources;
|
using Windows.ApplicationModel.Resources;
|
||||||
|
using Windows.Graphics.Display;
|
||||||
using Windows.Media.Core;
|
using Windows.Media.Core;
|
||||||
using Windows.Media.Playback;
|
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Controls.Primitives;
|
using Windows.UI.Xaml.Controls.Primitives;
|
||||||
|
using YoutubeExplode;
|
||||||
using YoutubeExplode.Models.ClosedCaptions;
|
using YoutubeExplode.Models.ClosedCaptions;
|
||||||
using YoutubeExplode.Models.MediaStreams;
|
using YoutubeExplode.Models.MediaStreams;
|
||||||
|
|
||||||
namespace FoxTube
|
namespace FoxTube
|
||||||
{
|
{
|
||||||
public delegate void QualityChangedEventHandler(object sender, MediaStreamInfo requestedQuality, MediaStreamInfoSet list);
|
|
||||||
public delegate void MinimodeChangedEventHandler(object sender, bool isOn);
|
public delegate void MinimodeChangedEventHandler(object sender, bool isOn);
|
||||||
|
|
||||||
|
public enum PlayerDisplayState { Normal, Minimized, Compact }
|
||||||
|
|
||||||
|
public class QualityComparer : IComparer<string>
|
||||||
|
{
|
||||||
|
public int Compare(string x, string y)
|
||||||
|
{
|
||||||
|
string[] xArr = x.Split('p');
|
||||||
|
string[] yArr = y.Split('p');
|
||||||
|
|
||||||
|
int qualityA = int.Parse(xArr[0]);
|
||||||
|
int qualityB = int.Parse(yArr[0]);
|
||||||
|
int framerateA = 30;
|
||||||
|
int framerateB = 30;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(xArr[1]))
|
||||||
|
framerateA = int.Parse(xArr[1]);
|
||||||
|
if (!string.IsNullOrWhiteSpace(yArr[1]))
|
||||||
|
framerateB = int.Parse(yArr[1]);
|
||||||
|
|
||||||
|
if (qualityA > qualityB)
|
||||||
|
return 1;
|
||||||
|
else if (qualityA < qualityB)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return framerateA - framerateB > 0 ? 1 : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Custom controls for media player. MARKUP IS IN **Themes/Generic.xaml**!!!
|
/// Custom controls for media player. MARKUP IS IN **Themes/Generic.xaml**!!!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class PlayerControls : MediaTransportControls
|
public sealed class PlayerControls : MediaTransportControls
|
||||||
{
|
{
|
||||||
public event RoutedEventHandler CloseRequested;
|
public event RoutedEventHandler CloseRequested;
|
||||||
public event RoutedEventHandler LiveRequested;
|
|
||||||
public event MinimodeChangedEventHandler MiniModeChanged;
|
public event MinimodeChangedEventHandler MiniModeChanged;
|
||||||
public event RoutedEventHandler NextRequested;
|
public event RoutedEventHandler NextRequested;
|
||||||
public event Event MuteClicked;
|
|
||||||
|
|
||||||
public event QualityChangedEventHandler QualityChanged;
|
#region Controls variables
|
||||||
|
Button minimize;
|
||||||
|
Button close;
|
||||||
|
Button miniview;
|
||||||
|
Button play;
|
||||||
|
Button next;
|
||||||
|
Button volumeMenu;
|
||||||
|
Button mute;
|
||||||
|
Button live;
|
||||||
|
Button fwd;
|
||||||
|
Button bwd;
|
||||||
|
Button captionsMenu;
|
||||||
|
Button settingsMenu;
|
||||||
|
Button fullscreen;
|
||||||
|
Button drag;
|
||||||
|
|
||||||
public MediaPlayer Player;
|
TextBlock title;
|
||||||
|
TextBlock channel;
|
||||||
|
TextBlock elapsed;
|
||||||
|
TextBlock remain;
|
||||||
|
|
||||||
|
Slider volume;
|
||||||
|
Slider seek;
|
||||||
|
ProgressBar seekIndicator;
|
||||||
|
|
||||||
|
ComboBox captions;
|
||||||
|
ComboBox quality;
|
||||||
|
|
||||||
|
ToggleSwitch captionsSwitch;
|
||||||
|
|
||||||
|
StackPanel rightFooter;
|
||||||
|
StackPanel leftFooter;
|
||||||
|
StackPanel rightHeader;
|
||||||
|
StackPanel centerStack;
|
||||||
|
Grid header;
|
||||||
|
Grid footer;
|
||||||
|
Grid center;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
PlayerDisplayState State { get; set; } = PlayerDisplayState.Normal;
|
||||||
|
|
||||||
|
public MediaElement Player { get; set; }
|
||||||
public PlayerAdvert Advert;
|
public PlayerAdvert Advert;
|
||||||
|
public LiveCaptions Caption;
|
||||||
|
|
||||||
|
TimeSpan timecodeBackup;
|
||||||
|
bool needUpdateTimecode = false;
|
||||||
|
|
||||||
|
public Video Meta { get; set; }
|
||||||
|
|
||||||
public IReadOnlyList<ClosedCaptionTrackInfo> ClosedCaptions { get; set; }
|
public IReadOnlyList<ClosedCaptionTrackInfo> ClosedCaptions { get; set; }
|
||||||
public MediaStreamInfoSet MediaStreams { get; set; }
|
public MediaStreamInfoSet MediaStreams { get; set; }
|
||||||
@@ -47,31 +120,22 @@ namespace FoxTube
|
|||||||
|
|
||||||
protected override void OnApplyTemplate()
|
protected override void OnApplyTemplate()
|
||||||
{
|
{
|
||||||
|
AssignControls();
|
||||||
|
|
||||||
isReady = true;
|
isReady = true;
|
||||||
|
|
||||||
Advert = GetTemplateChild("ad") as PlayerAdvert;
|
minimize.Click += Minimize_Click;
|
||||||
|
close.Click += Close_Click;
|
||||||
|
miniview.Click += Miniview_Click;
|
||||||
|
|
||||||
(GetTemplateChild("close") as Button).Click += Close_Click;
|
next.Click += Next_Click;
|
||||||
(GetTemplateChild("compactClose") as Button).Click += Close_Click;
|
volume.ValueChanged += Volume_ValueChanged;
|
||||||
|
live.Click += Live_Click;
|
||||||
|
|
||||||
(GetTemplateChild("minimize") as Button).Click += Minimize_Click;
|
captionsSwitch.Toggled += CaptionsSwitch_Toggled;
|
||||||
(GetTemplateChild("maximize") as Button).Click += Minimize_Click;
|
captions.SelectionChanged += Captions_SelectionChanged;
|
||||||
|
quality.SelectionChanged += Quality_SelectionChanged;
|
||||||
(GetTemplateChild("CompactOverlayButton") as Button).Click += CompactOverlay_Click;
|
seek.ValueChanged += Seek_ValueChanged;
|
||||||
|
|
||||||
(GetTemplateChild("qualitySelector") as ComboBox).SelectionChanged += QualitySelector_SelectionChanged;
|
|
||||||
|
|
||||||
(GetTemplateChild("ccSwitch") as ToggleSwitch).Toggled += CcSwitch_Toggled;
|
|
||||||
(GetTemplateChild("ccSelector") as ComboBox).SelectionChanged += CcSelector_SelectionChanged;
|
|
||||||
|
|
||||||
(GetTemplateChild("next") as Button).Click += (s, e) => NextRequested.Invoke(s, e);
|
|
||||||
|
|
||||||
(GetTemplateChild("AudioMuteButton") as Button).Click += Mute_Click;
|
|
||||||
(GetTemplateChild("VolumeSlider") as Slider).ValueChanged += Volume_ValueChanged;
|
|
||||||
|
|
||||||
(GetTemplateChild("ProgressSlider") as Slider).ValueChanged += ProgressSlider_ValueChanged;
|
|
||||||
|
|
||||||
(GetTemplateChild("goLive") as Button).Click += (s, e) => LiveRequested.Invoke(s, e);
|
|
||||||
|
|
||||||
if (queue.Count > 0)
|
if (queue.Count > 0)
|
||||||
foreach (Action i in queue)
|
foreach (Action i in queue)
|
||||||
@@ -80,96 +144,135 @@ namespace FoxTube
|
|||||||
base.OnApplyTemplate();
|
base.OnApplyTemplate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Minimize_Click(object sender, RoutedEventArgs e)
|
void AssignControls()
|
||||||
{
|
{
|
||||||
if (sender == (GetTemplateChild("minimize") as Button))
|
minimize = GetTemplateChild("MinimizeButton") as Button;
|
||||||
{
|
close = GetTemplateChild("CloseButton") as Button;
|
||||||
MiniModeChanged.Invoke(this, true);
|
miniview = GetTemplateChild("CompactOverlayButton") as Button;
|
||||||
SetMinimized();
|
play = GetTemplateChild("PlayPauseButton") as Button;
|
||||||
|
next = GetTemplateChild("NextButton") as Button;
|
||||||
|
volumeMenu = GetTemplateChild("VolumeMenuButton") as Button;
|
||||||
|
mute = GetTemplateChild("AudioMuteButton") as Button;
|
||||||
|
live = GetTemplateChild("PlayLiveButton") as Button;
|
||||||
|
fwd = GetTemplateChild("SkipForwardButton") as Button;
|
||||||
|
bwd = GetTemplateChild("SkipBackwardButton") as Button;
|
||||||
|
captionsMenu = GetTemplateChild("CaptionsMenuButton") as Button;
|
||||||
|
settingsMenu = GetTemplateChild("QualityMenuButton") as Button;
|
||||||
|
fullscreen = GetTemplateChild("FullWindowButton") as Button;
|
||||||
|
drag = GetTemplateChild("drag") as Button;
|
||||||
|
|
||||||
|
Advert = GetTemplateChild("AdvertControl") as PlayerAdvert;
|
||||||
|
Caption = GetTemplateChild("CaptionControl") as LiveCaptions;
|
||||||
|
|
||||||
|
title = GetTemplateChild("title") as TextBlock;
|
||||||
|
channel = GetTemplateChild("channel") as TextBlock;
|
||||||
|
elapsed = GetTemplateChild("TimeElapsedElement") as TextBlock;
|
||||||
|
remain = GetTemplateChild("TimeRemainingElement") as TextBlock;
|
||||||
|
|
||||||
|
volume = GetTemplateChild("VolumeSlider") as Slider;
|
||||||
|
seek = GetTemplateChild("ProgressSlider") as Slider;
|
||||||
|
seekIndicator = GetTemplateChild("SeekIndicator") as ProgressBar;
|
||||||
|
|
||||||
|
captions = GetTemplateChild("CaptionsSelector") as ComboBox;
|
||||||
|
quality = GetTemplateChild("QualitySelector") as ComboBox;
|
||||||
|
captionsSwitch = GetTemplateChild("CaptionsToggleSwitch") as ToggleSwitch;
|
||||||
|
|
||||||
|
rightFooter = GetTemplateChild("RightFooterControls") as StackPanel;
|
||||||
|
leftFooter = GetTemplateChild("LeftFooterControls") as StackPanel;
|
||||||
|
rightHeader = GetTemplateChild("RightHeaderControls") as StackPanel;
|
||||||
|
centerStack = GetTemplateChild("centerControls") as StackPanel;
|
||||||
|
header = GetTemplateChild("header") as Grid;
|
||||||
|
footer = GetTemplateChild("footer") as Grid;
|
||||||
|
center = GetTemplateChild("center") as Grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Seek_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
seekIndicator.Value = seek.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Quality_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (Meta.Snippet.LiveBroadcastContent == "live")
|
||||||
|
goto SetQuality;
|
||||||
|
if(!needUpdateTimecode)
|
||||||
|
timecodeBackup = Player.Position;
|
||||||
|
needUpdateTimecode = true;
|
||||||
|
Player.Pause();
|
||||||
|
Player.Source = null;
|
||||||
|
|
||||||
|
SetQuality:
|
||||||
|
object info = (quality.SelectedItem as ComboBoxItem).Tag;
|
||||||
|
if (info is MuxedStreamInfo)
|
||||||
|
Player.SetPlaybackSource(MediaSource.CreateFromUri((info as MuxedStreamInfo).Url.ToUri()));
|
||||||
|
else if (info is VideoStreamInfo)
|
||||||
|
Player.SetPlaybackSource(MediaSource.CreateFromUri(await ManifestGenerator.GetManifest(Meta, info as VideoStreamInfo, MediaStreams)));
|
||||||
|
else if (info is StreamQuality)
|
||||||
|
Player.SetPlaybackSource(MediaSource.CreateFromUri((info as StreamQuality).Url));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Captions_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if(Caption.IsActive)
|
||||||
|
{
|
||||||
|
Caption.Close();
|
||||||
|
Caption.Initialize((captions.SelectedItem as ComboBoxItem).Tag as ClosedCaptionTrackInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CaptionsSwitch_Toggled(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if(captionsSwitch.IsOn)
|
||||||
|
Caption.Initialize((captions.SelectedItem as ComboBoxItem).Tag as ClosedCaptionTrackInfo);
|
||||||
else
|
else
|
||||||
{
|
Caption.Close();
|
||||||
MiniModeChanged.Invoke(this, false);
|
|
||||||
SetNormal();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Minimize()
|
private void Live_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
Minimize_Click(GetTemplateChild("minimize"), null);
|
Player.Position = Player.NaturalDuration.TimeSpan;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProgressSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
|
private void Next_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
(GetTemplateChild("compactSeek") as ProgressBar).Value = e.NewValue;
|
NextRequested.Invoke(sender, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Mute_Click(object sender, RoutedEventArgs e)
|
private void Miniview_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (State == PlayerDisplayState.Compact)
|
||||||
|
Maximize();
|
||||||
|
else
|
||||||
|
EnterMiniview();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateVolumeIcon()
|
||||||
{
|
{
|
||||||
if (((GetTemplateChild("AudioMuteButton") as Button).Content as FontIcon).Glyph == "\xE74F")
|
|
||||||
Volume_ValueChanged(this, null);
|
Volume_ValueChanged(this, null);
|
||||||
else
|
|
||||||
((GetTemplateChild("AudioMuteButton") as Button).Content as FontIcon).Glyph = ((GetTemplateChild("volume") as Button).Content as FontIcon).Glyph = "\xE74F";
|
|
||||||
|
|
||||||
MuteClicked?.Invoke();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Volume_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
|
private void Volume_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
|
||||||
{
|
{
|
||||||
double v = (GetTemplateChild("VolumeSlider") as Slider).Value;
|
double v = volume.Value;
|
||||||
if (v == 0)
|
if (v == 0 || Player.IsMuted)
|
||||||
((GetTemplateChild("AudioMuteButton") as Button).Content as FontIcon).Glyph = ((GetTemplateChild("volume") as Button).Content as FontIcon).Glyph = "\xE74F";
|
volumeMenu.Content = mute.Content = "\xE74F";
|
||||||
else if (v <= 25 && v > 0)
|
else if (v <= 25 && v > 0)
|
||||||
((GetTemplateChild("AudioMuteButton") as Button).Content as FontIcon).Glyph = ((GetTemplateChild("volume") as Button).Content as FontIcon).Glyph = "\xE992";
|
volumeMenu.Content = mute.Content = "\xE992";
|
||||||
else if (v <= 50 && v > 25)
|
else if (v <= 50 && v > 25)
|
||||||
((GetTemplateChild("AudioMuteButton") as Button).Content as FontIcon).Glyph = ((GetTemplateChild("volume") as Button).Content as FontIcon).Glyph = "\xE993";
|
volumeMenu.Content = mute.Content = "\xE993";
|
||||||
else if (v <= 75 && v > 50)
|
else if (v <= 75 && v > 50)
|
||||||
((GetTemplateChild("AudioMuteButton") as Button).Content as FontIcon).Glyph = ((GetTemplateChild("volume") as Button).Content as FontIcon).Glyph = "\xE994";
|
volumeMenu.Content = mute.Content = "\xE994";
|
||||||
else if (v > 75)
|
else if (v > 75)
|
||||||
((GetTemplateChild("AudioMuteButton") as Button).Content as FontIcon).Glyph = ((GetTemplateChild("volume") as Button).Content as FontIcon).Glyph = "\xE995";
|
volumeMenu.Content = mute.Content = "\xE995";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CcSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
private void Player_MediaOpened(object sender, RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
CcSwitch_Toggled((GetTemplateChild("ccSwitch") as ToggleSwitch), null);
|
if (!needUpdateTimecode)
|
||||||
}
|
return;
|
||||||
|
|
||||||
private void CcSwitch_Toggled(object sender, RoutedEventArgs e)
|
needUpdateTimecode = false;
|
||||||
{
|
Player.Position = timecodeBackup;
|
||||||
if((GetTemplateChild("captions") as LiveCaptions).Player == null)
|
|
||||||
(GetTemplateChild("captions") as LiveCaptions).Player = Player;
|
|
||||||
|
|
||||||
if ((sender as ToggleSwitch).IsOn)
|
|
||||||
(GetTemplateChild("captions") as LiveCaptions).Initialize(((GetTemplateChild("ccSelector") as ComboBox).SelectedItem as ComboBoxItem).Tag as ClosedCaptionTrackInfo);
|
|
||||||
else
|
|
||||||
(GetTemplateChild("captions") as LiveCaptions).Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void QualitySelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
SettingsStorage.RememberedQuality = e.AddedItems[0] as string;
|
|
||||||
MediaStreamInfo item = MediaStreams.Muxed.Find(i => i.VideoQualityLabel.Contains(e.AddedItems[0] as string));
|
|
||||||
if (item == null)
|
|
||||||
item = MediaStreams.Video.Find(i => i.VideoQualityLabel == e.AddedItems[0] as string);
|
|
||||||
|
|
||||||
QualityChanged?.Invoke(sender, item, MediaStreams);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CompactOverlay_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if((sender as Button).Margin.Top > 0)
|
|
||||||
{
|
|
||||||
Button btnCompact = sender as Button;
|
|
||||||
(GetTemplateChild("center") as Grid).Children.Remove(btnCompact);
|
|
||||||
(GetTemplateChild("headerToolbar") as StackPanel).Children.Add(btnCompact);
|
|
||||||
|
|
||||||
btnCompact.Margin = new Thickness(0);
|
|
||||||
(btnCompact.Content as FontIcon).Glyph = "\xE2B3";
|
|
||||||
|
|
||||||
SetNormal();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SetCompactView();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Close_Click(object sender, RoutedEventArgs e)
|
private void Close_Click(object sender, RoutedEventArgs e)
|
||||||
@@ -177,179 +280,238 @@ namespace FoxTube
|
|||||||
CloseRequested?.Invoke(sender, e);
|
CloseRequested?.Invoke(sender, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCompactView()
|
private void Minimize_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
Button btn = GetTemplateChild("CompactOverlayButton") as Button;
|
if (State == PlayerDisplayState.Normal)
|
||||||
(GetTemplateChild("headerToolbar") as StackPanel).Children.Remove(btn);
|
Minimize();
|
||||||
(GetTemplateChild("center") as Grid).Children.Add(btn);
|
else
|
||||||
|
Maximize();
|
||||||
btn.Margin = new Thickness(0, 32, 0, 0);
|
|
||||||
(btn.Content as FontIcon).Glyph = "\xE2B4";
|
|
||||||
|
|
||||||
Button btnPlay = GetTemplateChild("PlayPauseButton") as Button;
|
|
||||||
(GetTemplateChild("leftStack") as StackPanel).Children.Remove(btnPlay);
|
|
||||||
(GetTemplateChild("centralStack") as StackPanel).Children.Add(btnPlay);
|
|
||||||
|
|
||||||
Button btnFwd = GetTemplateChild("SkipForwardButton") as Button;
|
|
||||||
(GetTemplateChild("rightStack") as StackPanel).Children.Remove(btnFwd);
|
|
||||||
(GetTemplateChild("centralStack") as StackPanel).Children.Insert(1, btnFwd);
|
|
||||||
|
|
||||||
Button btnBwd = GetTemplateChild("SkipBackwardButton") as Button;
|
|
||||||
(GetTemplateChild("rightStack") as StackPanel).Children.Remove(btnBwd);
|
|
||||||
(GetTemplateChild("centralStack") as StackPanel).Children.Insert(0, btnBwd);
|
|
||||||
|
|
||||||
(GetTemplateChild("header") as Grid).Visibility = Visibility.Collapsed;
|
|
||||||
(GetTemplateChild("centerBgr") as Grid).Visibility = Visibility.Visible;
|
|
||||||
(GetTemplateChild("center") as Grid).Visibility = Visibility.Visible;
|
|
||||||
(GetTemplateChild("footer") as Grid).Visibility = Visibility.Collapsed;
|
|
||||||
|
|
||||||
(GetTemplateChild("maximize") as Button).Visibility = Visibility.Collapsed;
|
|
||||||
(GetTemplateChild("compactClose") as Button).Visibility = Visibility.Collapsed;
|
|
||||||
|
|
||||||
(GetTemplateChild("dragholder") as Button).Visibility = Visibility.Visible;
|
|
||||||
|
|
||||||
(GetTemplateChild("captions") as LiveCaptions).Size = 15;
|
|
||||||
|
|
||||||
(GetTemplateChild("root") as Grid).RowDefinitions[1].Height = new GridLength(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetMinimized()
|
public void Minimize()
|
||||||
{
|
{
|
||||||
Button btnPlay = GetTemplateChild("PlayPauseButton") as Button;
|
if (State == PlayerDisplayState.Minimized)
|
||||||
(GetTemplateChild("leftStack") as StackPanel).Children.Remove(btnPlay);
|
return;
|
||||||
(GetTemplateChild("centralStack") as StackPanel).Children.Add(btnPlay);
|
|
||||||
|
|
||||||
Button btnFwd = GetTemplateChild("SkipForwardButton") as Button;
|
header.Children.Remove(minimize);
|
||||||
(GetTemplateChild("rightStack") as StackPanel).Children.Remove(btnFwd);
|
center.Children.Add(minimize);
|
||||||
(GetTemplateChild("centralStack") as StackPanel).Children.Insert(1, btnFwd);
|
rightHeader.Children.Remove(close);
|
||||||
|
center.Children.Add(close);
|
||||||
|
leftFooter.Children.Remove(play);
|
||||||
|
centerStack.Children.Add(play);
|
||||||
|
rightFooter.Children.Remove(fwd);
|
||||||
|
centerStack.Children.Add(fwd);
|
||||||
|
rightFooter.Children.Remove(bwd);
|
||||||
|
centerStack.Children.Insert(0, bwd);
|
||||||
|
|
||||||
Button btnBwd = GetTemplateChild("SkipBackwardButton") as Button;
|
header.Visibility = Visibility.Collapsed;
|
||||||
(GetTemplateChild("rightStack") as StackPanel).Children.Remove(btnBwd);
|
center.Visibility = Visibility.Visible;
|
||||||
(GetTemplateChild("centralStack") as StackPanel).Children.Insert(0, btnBwd);
|
footer.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
(GetTemplateChild("header") as Grid).Visibility = Visibility.Collapsed;
|
minimize.Content = "\xE010";
|
||||||
(GetTemplateChild("centerBgr") as Grid).Visibility = Visibility.Visible;
|
|
||||||
(GetTemplateChild("center") as Grid).Visibility = Visibility.Visible;
|
|
||||||
(GetTemplateChild("footer") as Grid).Visibility = Visibility.Collapsed;
|
|
||||||
|
|
||||||
(GetTemplateChild("compactClose") as Button).Visibility = Visibility.Visible;
|
MiniModeChanged.Invoke(this, true);
|
||||||
(GetTemplateChild("maximize") as Button).Visibility = Visibility.Visible;
|
Caption.Minimize();
|
||||||
|
|
||||||
(GetTemplateChild("captions") as LiveCaptions).Size = 15;
|
State = PlayerDisplayState.Minimized;
|
||||||
|
|
||||||
(GetTemplateChild("root") as Grid).RowDefinitions[1].Height = new GridLength(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetNormal()
|
public void Maximize()
|
||||||
{
|
{
|
||||||
Button btnPlay = GetTemplateChild("PlayPauseButton") as Button;
|
if (State == PlayerDisplayState.Normal)
|
||||||
(GetTemplateChild("centralStack") as StackPanel).Children.Remove(btnPlay);
|
return;
|
||||||
(GetTemplateChild("leftStack") as StackPanel).Children.Insert(0, btnPlay);
|
|
||||||
|
|
||||||
Button btnFwd = GetTemplateChild("SkipForwardButton") as Button;
|
if(State == PlayerDisplayState.Compact)
|
||||||
(GetTemplateChild("centralStack") as StackPanel).Children.Remove(btnFwd);
|
{
|
||||||
(GetTemplateChild("rightStack") as StackPanel).Children.Insert(0, btnFwd);
|
center.Children.Remove(miniview);
|
||||||
|
rightHeader.Children.Add(miniview);
|
||||||
|
centerStack.Children.Remove(play);
|
||||||
|
leftFooter.Children.Insert(0, play);
|
||||||
|
centerStack.Children.Remove(fwd);
|
||||||
|
rightFooter.Children.Insert(0, fwd);
|
||||||
|
centerStack.Children.Remove(bwd);
|
||||||
|
rightFooter.Children.Insert(0, bwd);
|
||||||
|
|
||||||
Button btnBwd = GetTemplateChild("SkipBackwardButton") as Button;
|
miniview.Margin = new Thickness();
|
||||||
(GetTemplateChild("centralStack") as StackPanel).Children.Remove(btnBwd);
|
miniview.Width = 50;
|
||||||
(GetTemplateChild("rightStack") as StackPanel).Children.Insert(0, btnBwd);
|
miniview.Height = 50;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
center.Children.Remove(minimize);
|
||||||
|
header.Children.Insert(0, minimize);
|
||||||
|
center.Children.Remove(close);
|
||||||
|
rightHeader.Children.Insert(0, close);
|
||||||
|
centerStack.Children.Remove(play);
|
||||||
|
leftFooter.Children.Insert(0, play);
|
||||||
|
centerStack.Children.Remove(fwd);
|
||||||
|
rightFooter.Children.Insert(0, fwd);
|
||||||
|
centerStack.Children.Remove(bwd);
|
||||||
|
rightFooter.Children.Insert(0, bwd);
|
||||||
|
|
||||||
(GetTemplateChild("header") as Grid).Visibility = Visibility.Visible;
|
MiniModeChanged.Invoke(this, false);
|
||||||
(GetTemplateChild("centerBgr") as Grid).Visibility = Visibility.Collapsed;
|
|
||||||
(GetTemplateChild("center") as Grid).Visibility = Visibility.Collapsed;
|
|
||||||
(GetTemplateChild("footer") as Grid).Visibility = Visibility.Visible;
|
|
||||||
|
|
||||||
(GetTemplateChild("captions") as LiveCaptions).Size = 24;
|
|
||||||
|
|
||||||
(GetTemplateChild("dragholder") as Button).Visibility = Visibility.Collapsed;
|
|
||||||
|
|
||||||
(GetTemplateChild("root") as Grid).RowDefinitions[1].Height = new GridLength(1, GridUnitType.Auto);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetMeta(string title, string channel)
|
drag.Visibility = Visibility.Collapsed;
|
||||||
|
header.Visibility = Visibility.Visible;
|
||||||
|
center.Visibility = Visibility.Collapsed;
|
||||||
|
footer.Visibility = Visibility.Visible;
|
||||||
|
miniview.Content = "\xE2B3";
|
||||||
|
minimize.Content = "\xE011";
|
||||||
|
Caption.Maximize();
|
||||||
|
|
||||||
|
State = PlayerDisplayState.Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnterMiniview()
|
||||||
|
{
|
||||||
|
if (State == PlayerDisplayState.Compact)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rightHeader.Children.Remove(miniview);
|
||||||
|
center.Children.Add(miniview);
|
||||||
|
leftFooter.Children.Remove(play);
|
||||||
|
centerStack.Children.Add(play);
|
||||||
|
rightFooter.Children.Remove(fwd);
|
||||||
|
centerStack.Children.Add(fwd);
|
||||||
|
rightFooter.Children.Remove(bwd);
|
||||||
|
centerStack.Children.Insert(0, bwd);
|
||||||
|
|
||||||
|
drag.Visibility = Visibility.Visible;
|
||||||
|
header.Visibility = Visibility.Collapsed;
|
||||||
|
center.Visibility = Visibility.Visible;
|
||||||
|
footer.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
|
miniview.Margin = new Thickness(0, 32, 0, 0);
|
||||||
|
miniview.Width = 47;
|
||||||
|
miniview.Height = 47;
|
||||||
|
|
||||||
|
miniview.Content = "\xE2B4";
|
||||||
|
Caption.Minimize();
|
||||||
|
|
||||||
|
State = PlayerDisplayState.Compact;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void Load(Video meta)
|
||||||
{
|
{
|
||||||
if(!isReady)
|
if(!isReady)
|
||||||
{
|
{
|
||||||
queue.Enqueue(() => SetMeta(title, channel));
|
queue.Enqueue(() => Load(meta));
|
||||||
return;
|
|
||||||
}
|
|
||||||
(GetTemplateChild("title") as TextBlock).Text = title;
|
|
||||||
(GetTemplateChild("author") as TextBlock).Text = channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetCaptions(IReadOnlyList<ClosedCaptionTrackInfo> list)
|
|
||||||
{
|
|
||||||
if (!isReady)
|
|
||||||
{
|
|
||||||
queue.Enqueue(() => SetCaptions(list));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClosedCaptions = list;
|
Player.MediaOpened += Player_MediaOpened;
|
||||||
|
|
||||||
if (list.Count > 0)
|
Meta = meta;
|
||||||
|
title.Text = meta.Snippet.Title;
|
||||||
|
channel.Text = meta.Snippet.ChannelTitle;
|
||||||
|
|
||||||
|
MediaStreams = await new YoutubeClient().GetVideoMediaStreamInfosAsync(meta.Id);
|
||||||
|
|
||||||
|
if (meta.Snippet.LiveBroadcastContent == "none")
|
||||||
{
|
{
|
||||||
foreach(ClosedCaptionTrackInfo i in list)
|
ClosedCaptions = await new YoutubeClient().GetVideoClosedCaptionTrackInfosAsync(meta.Id);
|
||||||
(GetTemplateChild("ccSelector") as ComboBox).Items.Add(new ComboBoxItem()
|
|
||||||
|
/*foreach (MuxedStreamInfo i in MediaStreams.Muxed)
|
||||||
|
quality.Items.Add(new ComboBoxItem
|
||||||
|
{
|
||||||
|
Content = $"{i.VideoQualityLabel} (muxed)",
|
||||||
|
Tag = i
|
||||||
|
});
|
||||||
|
foreach (VideoStreamInfo i in MediaStreams.Video)
|
||||||
|
quality.Items.Add(new ComboBoxItem
|
||||||
|
{
|
||||||
|
Content = $"{i.VideoQualityLabel} (video-only)",
|
||||||
|
Tag = i
|
||||||
|
});
|
||||||
|
foreach (AudioStreamInfo i in MediaStreams.Audio)
|
||||||
|
quality.Items.Add(new ComboBoxItem
|
||||||
|
{
|
||||||
|
Content = $"{i.Bitrate} (audio-only)",
|
||||||
|
Tag = i
|
||||||
|
});*/
|
||||||
|
|
||||||
|
uint screenHeight = DisplayInformation.GetForCurrentView().ScreenHeightInRawPixels;
|
||||||
|
|
||||||
|
List<string> qualityList = MediaStreams.GetAllVideoQualityLabels().ToList();
|
||||||
|
qualityList.Sort(new QualityComparer());
|
||||||
|
qualityList.Reverse();
|
||||||
|
|
||||||
|
foreach (string i in qualityList)
|
||||||
|
{
|
||||||
|
object tag;
|
||||||
|
if (MediaStreams.Muxed.Any(m => m.VideoQualityLabel == i && m.Resolution.Height <= screenHeight))
|
||||||
|
tag = MediaStreams.Muxed.Find(m => m.VideoQualityLabel == i);
|
||||||
|
else if (MediaStreams.Video.Any(m => m.VideoQualityLabel == i && m.Resolution.Height <= screenHeight && m.Container.GetFileExtension() == "webm"))
|
||||||
|
tag = MediaStreams.Video.Find(m => m.VideoQualityLabel == i && m.Container.GetFileExtension() == "webm");
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
quality.Items.Add(new ComboBoxItem
|
||||||
|
{
|
||||||
|
Content = i,
|
||||||
|
Tag = tag
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
string s = SettingsStorage.VideoQuality == "remember" ? SettingsStorage.RememberedQuality : SettingsStorage.VideoQuality;
|
||||||
|
|
||||||
|
if (quality.Items.Any(i => (i as ComboBoxItem).Content as string == s))
|
||||||
|
quality.SelectedItem = quality.Items.Find(i => (i as ComboBoxItem).Content as string == s);
|
||||||
|
else
|
||||||
|
quality.SelectedIndex = 0;
|
||||||
|
|
||||||
|
|
||||||
|
if (ClosedCaptions.Count == 0)
|
||||||
|
{
|
||||||
|
captionsMenu.Visibility = Visibility.Collapsed;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ClosedCaptionTrackInfo i in ClosedCaptions)
|
||||||
|
captions.Items.Add(new ComboBoxItem
|
||||||
{
|
{
|
||||||
Content = string.Format("{0} {1}", CultureInfo.GetCultureInfo(i.Language.Code).DisplayName, i.IsAutoGenerated ? ResourceLoader.GetForCurrentView("VideoPage").GetString("/VideoPage/generatedCaption") : ""),
|
Content = string.Format("{0} {1}", CultureInfo.GetCultureInfo(i.Language.Code).DisplayName, i.IsAutoGenerated ? ResourceLoader.GetForCurrentView("VideoPage").GetString("/VideoPage/generatedCaption") : ""),
|
||||||
Tag = i
|
Tag = i
|
||||||
});
|
});
|
||||||
|
|
||||||
ClosedCaptionTrackInfo item = list.Find(i => SettingsStorage.RelevanceLanguage.Contains(i.Language.Code)) ?? list.Find(i => "en-US".Contains(i.Language.Code));
|
ClosedCaptionTrackInfo item = ClosedCaptions.Find(i => SettingsStorage.RelevanceLanguage.Contains(i.Language.Code)) ?? ClosedCaptions.Find(i => "en-US".Contains(i.Language.Code));
|
||||||
if (item == null)
|
if (item == null)
|
||||||
item = list.First();
|
item = ClosedCaptions.First();
|
||||||
|
|
||||||
(GetTemplateChild("ccSelector") as ComboBox).SelectedItem = (GetTemplateChild("ccSelector") as ComboBox).Items.Find(i => (i as ComboBoxItem).Tag == item);
|
captions.SelectedItem = captions.Items.Find(i => (i as ComboBoxItem).Tag as ClosedCaptionTrackInfo == item);
|
||||||
|
|
||||||
|
Caption.Player = Player;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
(GetTemplateChild("cc") as Button).Visibility = Visibility.Collapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetQualities(MediaStreamInfoSet list)
|
|
||||||
{
|
{
|
||||||
if (!isReady)
|
captionsMenu.Visibility = Visibility.Collapsed;
|
||||||
|
seek.Visibility = Visibility.Collapsed;
|
||||||
|
live.Visibility = Visibility.Visible;
|
||||||
|
remain.Visibility = Visibility.Collapsed;
|
||||||
|
elapsed.FontSize = 24;
|
||||||
|
Grid.SetRow(elapsed, 0);
|
||||||
|
Grid.SetRowSpan(elapsed, 2);
|
||||||
|
elapsed.HorizontalAlignment = HorizontalAlignment.Right;
|
||||||
|
fwd.Visibility = Visibility.Collapsed;
|
||||||
|
bwd.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
|
List<StreamQuality> list = await ManifestGenerator.ResolveLiveSteream(MediaStreams.HlsLiveStreamUrl);
|
||||||
|
|
||||||
|
foreach (StreamQuality i in list)
|
||||||
|
quality.Items.Add(new ComboBoxItem
|
||||||
{
|
{
|
||||||
queue.Enqueue(() => SetQualities(list));
|
Content = i.Resolution,
|
||||||
return;
|
Tag = i
|
||||||
}
|
});
|
||||||
|
|
||||||
MediaStreams = list;
|
|
||||||
|
|
||||||
List<VideoQuality> q = list.GetAllVideoQualities().ToList();
|
|
||||||
q.Sort();
|
|
||||||
q.Reverse();
|
|
||||||
List<string> labels = new List<string>();
|
|
||||||
q.ForEach(i => labels.Add(i.GetVideoQualityLabel()));
|
|
||||||
(GetTemplateChild("qualitySelector") as ComboBox).ItemsSource = labels;
|
|
||||||
|
|
||||||
string s = SettingsStorage.VideoQuality == "remember" ? SettingsStorage.RememberedQuality : SettingsStorage.VideoQuality;
|
string s = SettingsStorage.VideoQuality == "remember" ? SettingsStorage.RememberedQuality : SettingsStorage.VideoQuality;
|
||||||
|
|
||||||
if (labels.Contains(s))
|
if (quality.Items.Any(i => (i as ComboBoxItem).Content as string == s))
|
||||||
(GetTemplateChild("qualitySelector") as ComboBox).SelectedItem = s;
|
quality.SelectedItem = quality.Items.Find(i => (i as ComboBoxItem).Content as string == s);
|
||||||
else
|
else
|
||||||
(GetTemplateChild("qualitySelector") as ComboBox).SelectedIndex = 0;
|
quality.SelectedIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetStream(string url)
|
|
||||||
{
|
|
||||||
if (!isReady)
|
|
||||||
{
|
|
||||||
queue.Enqueue(() => SetStream(url));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
(GetTemplateChild("goLive") as Button).Visibility = Visibility.Visible;
|
|
||||||
(GetTemplateChild("sliderPan") as Grid).Children.Remove(GetTemplateChild("TimeElapsedElement") as TextBlock);
|
|
||||||
(GetTemplateChild("rightStack") as StackPanel).Children.Insert(0, GetTemplateChild("TimeElapsedElement") as TextBlock);
|
|
||||||
(GetTemplateChild("TimeElapsedElement") as TextBlock).VerticalAlignment = VerticalAlignment.Center;
|
|
||||||
(GetTemplateChild("TimeElapsedElement") as TextBlock).FontSize = 18;
|
|
||||||
(GetTemplateChild("TimeElapsedElement") as TextBlock).Margin = new Thickness(10, 0, 10, 0);
|
|
||||||
(GetTemplateChild("sliderPan") as Grid).Visibility = Visibility.Collapsed;
|
|
||||||
(GetTemplateChild("cc") as Button).Visibility = Visibility.Collapsed;
|
|
||||||
(GetTemplateChild("quality") as Button).Visibility = Visibility.Collapsed;
|
|
||||||
|
|
||||||
Player.Source = MediaSource.CreateFromUri(url.ToUri());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,16 +8,17 @@
|
|||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="1080"
|
d:DesignHeight="1080"
|
||||||
d:DesignWidth="1920"
|
d:DesignWidth="1920"
|
||||||
RequestedTheme="Dark">
|
RequestedTheme="Dark"
|
||||||
|
Visibility="Collapsed">
|
||||||
|
|
||||||
<Grid Background="{StaticResource SystemChromeMediumColor}">
|
<Grid Background="{StaticResource SystemChromeMediumColor}">
|
||||||
<MediaPlayerElement Name="videoSource" AreTransportControlsEnabled="True" PosterSource="ms-appx:///Assets/videoThumbSample.png">
|
<MediaElement Name="videoSource" AreTransportControlsEnabled="True" VolumeChanged="VideoSource_VolumeChanged" CurrentStateChanged="VideoSource_CurrentStateChanged" MarkerReached="VideoSource_MarkerReached" PosterSource="ms-appx:///Assets/videoThumbSample.png">
|
||||||
<MediaPlayerElement.TransportControls>
|
<MediaElement.TransportControls>
|
||||||
<foxtube:PlayerControls IsCompactOverlayButtonVisible="True" IsCompactOverlayEnabled="True"
|
<foxtube:PlayerControls IsCompactOverlayButtonVisible="True" IsCompactOverlayEnabled="True"
|
||||||
IsFullWindowButtonVisible="True" IsFullWindowEnabled="True"
|
IsFullWindowButtonVisible="True" IsFullWindowEnabled="True"
|
||||||
IsSkipBackwardButtonVisible="True" IsSkipBackwardEnabled="True"
|
IsSkipBackwardButtonVisible="True" IsSkipBackwardEnabled="True"
|
||||||
IsSkipForwardButtonVisible="True" IsSkipForwardEnabled="True"/>
|
IsSkipForwardButtonVisible="True" IsSkipForwardEnabled="True"/>
|
||||||
</MediaPlayerElement.TransportControls>
|
</MediaElement.TransportControls>
|
||||||
</MediaPlayerElement>
|
</MediaElement>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ using Windows.Storage.Pickers;
|
|||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
using Windows.Media.MediaProperties;
|
using Windows.Media.MediaProperties;
|
||||||
using FoxTube.Controls.Player;
|
using FoxTube.Controls.Player;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Windows.UI.Xaml.Media;
|
||||||
|
|
||||||
namespace FoxTube
|
namespace FoxTube
|
||||||
{
|
{
|
||||||
@@ -33,15 +35,7 @@ namespace FoxTube
|
|||||||
public event ObjectEventHandler MiniMode;
|
public event ObjectEventHandler MiniMode;
|
||||||
|
|
||||||
public PlayerControls Controls => videoSource.TransportControls as PlayerControls;
|
public PlayerControls Controls => videoSource.TransportControls as PlayerControls;
|
||||||
public MediaPlayer Player { get; } = new MediaPlayer();
|
public MediaElement Player => videoSource;
|
||||||
public TimeSpan Position
|
|
||||||
{
|
|
||||||
get { return videoSource.MediaPlayer.PlaybackSession.Position; }
|
|
||||||
set { videoSource.MediaPlayer.PlaybackSession.Position = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
//TimeSpan timecodeBackup;
|
|
||||||
//bool needUpdateTimecode = false;
|
|
||||||
|
|
||||||
SystemMediaTransportControls systemControls;
|
SystemMediaTransportControls systemControls;
|
||||||
|
|
||||||
@@ -50,7 +44,7 @@ namespace FoxTube
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void Initialize(Video meta, string channelAvatar, bool privateMode = false)
|
public void Initialize(Video meta, string channelAvatar, bool privateMode = false)
|
||||||
{
|
{
|
||||||
incognito = privateMode;
|
incognito = privateMode;
|
||||||
item = meta;
|
item = meta;
|
||||||
@@ -61,58 +55,41 @@ namespace FoxTube
|
|||||||
};
|
};
|
||||||
|
|
||||||
videoSource.PosterSource = new BitmapImage((meta.Snippet.Thumbnails.Maxres ?? meta.Snippet.Thumbnails.Medium).Url.ToUri());
|
videoSource.PosterSource = new BitmapImage((meta.Snippet.Thumbnails.Maxres ?? meta.Snippet.Thumbnails.Medium).Url.ToUri());
|
||||||
Controls.SetMeta(meta.Snippet.Localized.Title, meta.Snippet.ChannelTitle);
|
|
||||||
|
|
||||||
if (item.Snippet.LiveBroadcastContent == "none")
|
if (item.Snippet.LiveBroadcastContent == "none")
|
||||||
{
|
{
|
||||||
InitializeContols();
|
InitializeContols();
|
||||||
// TODO: make ads live again
|
Controls.Load(item);
|
||||||
/*if (Methods.GetDuration(item.ContentDetails.Duration).TotalMinutes > 5)
|
|
||||||
Player.PlaybackSession.Add(new Windows.UI.Xaml.Media.TimelineMarker { Time = Methods.GetDuration(item.ContentDetails.Duration) - TimeSpan.FromMinutes(1) });
|
if (Methods.GetDuration(item.ContentDetails.Duration).TotalMinutes > 5)
|
||||||
|
videoSource.Markers.Add(new TimelineMarker { Time = Methods.GetDuration(item.ContentDetails.Duration) - TimeSpan.FromMinutes(1) });
|
||||||
if(Methods.GetDuration(item.ContentDetails.Duration).TotalMinutes >= 60)
|
if(Methods.GetDuration(item.ContentDetails.Duration).TotalMinutes >= 60)
|
||||||
for (int k = 1; k < Methods.GetDuration(item.ContentDetails.Duration).TotalMinutes / 30; k++)
|
for (int k = 1; k < Methods.GetDuration(item.ContentDetails.Duration).TotalMinutes / 30; k++)
|
||||||
videoSource.Markers.Add(new Windows.UI.Xaml.Media.TimelineMarker { Time = TimeSpan.FromMinutes(k * 30) });*/
|
videoSource.Markers.Add(new TimelineMarker { Time = TimeSpan.FromMinutes(k * 30) });
|
||||||
|
|
||||||
Controls.SetQualities(await new YoutubeClient().GetVideoMediaStreamInfosAsync(item.Id));
|
if (!privateMode)
|
||||||
Controls.SetCaptions(await new YoutubeClient().GetVideoClosedCaptionTrackInfosAsync(item.Id));
|
HistorySet.Update(history);
|
||||||
}
|
}
|
||||||
else if (item.Snippet.LiveBroadcastContent == "live")
|
else if (item.Snippet.LiveBroadcastContent == "live")
|
||||||
{
|
{
|
||||||
InitializeContols();
|
InitializeContols();
|
||||||
Controls.IsSkipBackwardButtonVisible = false;
|
Controls.Load(item);
|
||||||
Controls.IsSkipForwardButtonVisible = false;
|
|
||||||
Controls.LiveRequested += Controls_LiveRequested;
|
|
||||||
object i = await new YoutubeClient().GetVideoMediaStreamInfosAsync(item.Id);
|
|
||||||
Controls.SetStream((await new YoutubeClient().GetVideoMediaStreamInfosAsync(item.Id)).HlsLiveStreamUrl);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
videoSource.AreTransportControlsEnabled = false;
|
videoSource.AreTransportControlsEnabled = false;
|
||||||
|
|
||||||
if (!privateMode)
|
|
||||||
HistorySet.Update(history);
|
|
||||||
|
|
||||||
Visibility = Visibility.Visible;
|
Visibility = Visibility.Visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Controls_LiveRequested(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
Position = Player.PlaybackSession.NaturalDuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void InitializeContols()
|
public void InitializeContols()
|
||||||
{
|
{
|
||||||
videoSource.SetMediaPlayer(Player);
|
videoSource.Volume = SettingsStorage.Volume;
|
||||||
Player.Volume = SettingsStorage.Volume;
|
videoSource.AutoPlay = SettingsStorage.Autoplay;
|
||||||
|
|
||||||
Player.CurrentStateChanged += VideoSource_CurrentStateChanged;
|
|
||||||
Player.MediaOpened += VideoSource_MediaOpened;
|
|
||||||
Player.VolumeChanged += VideoSource_VolumeChanged;
|
|
||||||
|
|
||||||
Controls.CloseRequested += Controls_CloseRequested;
|
Controls.CloseRequested += Controls_CloseRequested;
|
||||||
Controls.NextRequested += (s, e) => NextClicked?.Invoke();
|
Controls.NextRequested += (s, e) => NextClicked?.Invoke();
|
||||||
Controls.QualityChanged += Controls_QualityChanged;
|
|
||||||
Controls.MiniModeChanged += Controls_MiniModeChanged;
|
Controls.MiniModeChanged += Controls_MiniModeChanged;
|
||||||
Controls.Player = Player;
|
Controls.Player = videoSource;
|
||||||
|
|
||||||
#region System Media Transport Controls
|
#region System Media Transport Controls
|
||||||
systemControls = SystemMediaTransportControls.GetForCurrentView();
|
systemControls = SystemMediaTransportControls.GetForCurrentView();
|
||||||
@@ -131,6 +108,25 @@ namespace FoxTube
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void SystemControls_Engaged(SystemMediaTransportControls sender, SystemMediaTransportControlsButtonPressedEventArgs args)
|
||||||
|
{
|
||||||
|
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||||
|
{
|
||||||
|
switch (args.Button)
|
||||||
|
{
|
||||||
|
case SystemMediaTransportControlsButton.Play:
|
||||||
|
videoSource.Play();
|
||||||
|
break;
|
||||||
|
case SystemMediaTransportControlsButton.Pause:
|
||||||
|
videoSource.Pause();
|
||||||
|
break;
|
||||||
|
case SystemMediaTransportControlsButton.Next:
|
||||||
|
NextClicked?.Invoke();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void Controls_MiniModeChanged(object sender, bool e)
|
public void Controls_MiniModeChanged(object sender, bool e)
|
||||||
{
|
{
|
||||||
videoSource.IsFullWindow = false;
|
videoSource.IsFullWindow = false;
|
||||||
@@ -143,101 +139,46 @@ namespace FoxTube
|
|||||||
Controls.Minimize();
|
Controls.Minimize();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Controls_QualityChanged(object sender, MediaStreamInfo requestedQuality, MediaStreamInfoSet list)
|
|
||||||
{
|
|
||||||
Player.Pause();
|
|
||||||
|
|
||||||
Player.Source = MediaSource.CreateFromUri(await ManifestGenerator.GetManifest(item, requestedQuality as VideoStreamInfo, list));
|
|
||||||
|
|
||||||
//await ManifestGenerator.GetManifest(item, requestedQuality as VideoStreamInfo, list);
|
|
||||||
/*FileOpenPicker picker = new FileOpenPicker();
|
|
||||||
picker.FileTypeFilter.Add(".mpd");*/
|
|
||||||
|
|
||||||
//Player.Source = MediaSource.CreateFromUri("https://foxsharp.000webhostapp.com/dash_sample.mpd".ToUri());
|
|
||||||
|
|
||||||
/*timecodeBackup = videoSource.Position;
|
|
||||||
needUpdateTimecode = true;
|
|
||||||
|
|
||||||
if (requestedQuality is MuxedStreamInfo)
|
|
||||||
videoSource.Source = requestedQuality.Url.ToUri();
|
|
||||||
else
|
|
||||||
processor.Start(requestedQuality as VideoStreamInfo, list);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Controls_CloseRequested(object sender, RoutedEventArgs e)
|
public void Controls_CloseRequested(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if(systemControls != null)
|
videoSource.Pause();
|
||||||
systemControls.IsEnabled = false;
|
systemControls.IsEnabled = false;
|
||||||
|
videoSource.Source = null;
|
||||||
|
|
||||||
if (!incognito)
|
if (!incognito && item.Snippet.LiveBroadcastContent == "none")
|
||||||
{
|
{
|
||||||
history.LeftOn = Player.PlaybackSession.Position;
|
history.LeftOn = videoSource.Position;
|
||||||
HistorySet.Update(history);
|
HistorySet.Update(history);
|
||||||
}
|
}
|
||||||
|
|
||||||
Methods.MainPage.CloseVideo();
|
Methods.MainPage.CloseVideo();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void SystemControls_Engaged(SystemMediaTransportControls sender, SystemMediaTransportControlsButtonPressedEventArgs args)
|
|
||||||
{
|
|
||||||
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
|
||||||
{
|
|
||||||
switch (args.Button)
|
|
||||||
{
|
|
||||||
case SystemMediaTransportControlsButton.Play:
|
|
||||||
Player.Play();
|
|
||||||
break;
|
|
||||||
case SystemMediaTransportControlsButton.Pause:
|
|
||||||
Player.Pause();
|
|
||||||
break;
|
|
||||||
case SystemMediaTransportControlsButton.Next:
|
|
||||||
NextClicked?.Invoke();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Pause()
|
public void Pause()
|
||||||
{
|
{
|
||||||
Player.Pause();
|
videoSource.Pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void VideoSource_CurrentStateChanged(MediaPlayer sender, object e)
|
private void VideoSource_CurrentStateChanged(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
switch (Player.PlaybackSession.PlaybackState)
|
systemControls.PlaybackStatus = videoSource.CurrentState == MediaElementState.Playing ? MediaPlaybackStatus.Playing : MediaPlaybackStatus.Paused;
|
||||||
|
|
||||||
|
if(videoSource.CurrentState == MediaElementState.Paused)
|
||||||
|
if (!incognito && item.Snippet.LiveBroadcastContent == "none")
|
||||||
{
|
{
|
||||||
case MediaPlaybackState.Buffering:
|
history.LeftOn = videoSource.Position;
|
||||||
case MediaPlaybackState.None:
|
|
||||||
case MediaPlaybackState.Opening:
|
|
||||||
case MediaPlaybackState.Paused:
|
|
||||||
systemControls.PlaybackStatus = MediaPlaybackStatus.Paused;
|
|
||||||
if (!incognito)
|
|
||||||
{
|
|
||||||
history.LeftOn = Player.PlaybackSession.Position;
|
|
||||||
HistorySet.Update(history);
|
HistorySet.Update(history);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case MediaPlaybackState.Playing:
|
|
||||||
systemControls.PlaybackStatus = MediaPlaybackStatus.Playing;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void VideoSource_MediaOpened(MediaPlayer sender, object e)
|
private void VideoSource_VolumeChanged(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
/*if (!needUpdateTimecode)
|
if(videoSource.Volume != 0)
|
||||||
return;
|
SettingsStorage.Volume = videoSource.Volume;
|
||||||
|
Controls.UpdateVolumeIcon();
|
||||||
videoSource.Position = timecodeBackup;
|
|
||||||
needUpdateTimecode = false;*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void VideoSource_VolumeChanged(MediaPlayer sender, object e)
|
private void VideoSource_MarkerReached(object sender, TimelineMarkerRoutedEventArgs e)
|
||||||
{
|
|
||||||
SettingsStorage.Volume = Player.Volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void VideoSource_MarkerReached(object sender, Windows.UI.Xaml.Media.TimelineMarkerRoutedEventArgs e)
|
|
||||||
{
|
{
|
||||||
Controls.Advert.PushAdvert();
|
Controls.Advert.PushAdvert();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ namespace FoxTube.Controls
|
|||||||
Initialize(id, playlist);
|
Initialize(id, playlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public VideoCard(Video meta, string playlist = null)
|
public VideoCard(Video meta, string playlist = null)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -108,6 +109,7 @@ namespace FoxTube.Controls
|
|||||||
watched.Visibility = Visibility.Visible;
|
watched.Visibility = Visibility.Visible;
|
||||||
if (HistorySet.Items.Exists(i => i.Id == item.Id))
|
if (HistorySet.Items.Exists(i => i.Id == item.Id))
|
||||||
{
|
{
|
||||||
|
history = HistorySet.Items.Find(i => i.Id == item.Id);
|
||||||
watched.Visibility = Visibility.Visible;
|
watched.Visibility = Visibility.Visible;
|
||||||
leftOn.Value = 100 * HistorySet.Items.Find(i => i.Id == item.Id).LeftOn.TotalSeconds / Methods.GetDuration(item.ContentDetails.Duration).TotalSeconds;
|
leftOn.Value = 100 * HistorySet.Items.Find(i => i.Id == item.Id).LeftOn.TotalSeconds / Methods.GetDuration(item.ContentDetails.Duration).TotalSeconds;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -430,7 +430,7 @@
|
|||||||
<Version>10.1811.22001</Version>
|
<Version>10.1811.22001</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.AppCenter.Analytics">
|
<PackageReference Include="Microsoft.AppCenter.Analytics">
|
||||||
<Version>1.14.0</Version>
|
<Version>2.0.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
|
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
|
||||||
<Version>6.2.8</Version>
|
<Version>6.2.8</Version>
|
||||||
@@ -451,7 +451,7 @@
|
|||||||
<Version>4.3.2</Version>
|
<Version>4.3.2</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="YoutubeExplode">
|
<PackageReference Include="YoutubeExplode">
|
||||||
<Version>4.7.0-beta</Version>
|
<Version>4.7.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -444,8 +444,8 @@ namespace FoxTube.Pages
|
|||||||
private async void openBrowser_Click(object sender, RoutedEventArgs e)
|
private async void openBrowser_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
player.Pause();
|
player.Pause();
|
||||||
string timecode = player.Position.TotalSeconds > 10 ?
|
string timecode = player.Player.Position.TotalSeconds > 10 ?
|
||||||
"&t=" + (int)player.Position.TotalSeconds + "s" : string.Empty;
|
"&t=" + (int)player.Player.Position.TotalSeconds + "s" : string.Empty;
|
||||||
|
|
||||||
await Launcher.LaunchUriAsync($"https://www.youtube.com/watch?v={videoId}{timecode}".ToUri());
|
await Launcher.LaunchUriAsync($"https://www.youtube.com/watch?v={videoId}{timecode}".ToUri());
|
||||||
}
|
}
|
||||||
@@ -778,7 +778,7 @@ namespace FoxTube.Pages
|
|||||||
|
|
||||||
private void Left_Click(object sender, RoutedEventArgs e)
|
private void Left_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
Player.Position = history.LeftOn;
|
Player.Player.Position = history.LeftOn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,7 @@
|
|||||||
xmlns:adverts="using:FoxTube.Controls.Adverts">
|
xmlns:adverts="using:FoxTube.Controls.Adverts">
|
||||||
|
|
||||||
<Style TargetType="local:PlayerControls">
|
<Style TargetType="local:PlayerControls">
|
||||||
<Setter Property="IsTabStop" Value="False" />
|
|
||||||
<Setter Property="Background" Value="Transparent" />
|
<Setter Property="Background" Value="Transparent" />
|
||||||
<Setter Property="FlowDirection" Value="LeftToRight" />
|
|
||||||
<Setter Property="UseSystemFocusVisuals" Value="True" />
|
<Setter Property="UseSystemFocusVisuals" Value="True" />
|
||||||
<Setter Property="IsTextScaleFactorEnabled" Value="False" />
|
<Setter Property="IsTextScaleFactorEnabled" Value="False" />
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
@@ -20,69 +18,24 @@
|
|||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.Resources>
|
<Grid.Resources>
|
||||||
<Style x:Key="AppBarButtonStyle" TargetType="AppBarButton">
|
|
||||||
<Setter Property="Width" Value="{ThemeResource MTCMediaButtonWidth}" />
|
|
||||||
<Setter Property="Height" Value="{ThemeResource MTCMediaButtonHeight}" />
|
|
||||||
<Setter Property="AllowFocusOnInteraction" Value="True" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style x:Key="CommandBarStyle" TargetType="CommandBar">
|
|
||||||
<Setter Property="Height" Value="{ThemeResource MTCMediaButtonHeight}" />
|
|
||||||
<Setter Property="Background" Value="Transparent" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style x:Key="MediaTextBlockStyle" TargetType="TextBlock">
|
|
||||||
<Setter Property="VerticalAlignment" Value="Center" />
|
|
||||||
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}" />
|
|
||||||
<Setter Property="FontSize" Value="{ThemeResource MTCMediaFontSize}" />
|
|
||||||
<Setter Property="FontFamily" Value="{ThemeResource MTCMediaFontFamily}" />
|
|
||||||
<Setter Property="Style" Value="{ThemeResource CaptionTextBlockStyle }" />
|
|
||||||
<Setter Property="IsTextScaleFactorEnabled" Value="False" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style x:Key="PlayerSeek" TargetType="Slider">
|
<Style x:Key="PlayerSeek" TargetType="Slider">
|
||||||
<Setter Property="Background" Value="{ThemeResource SliderTrackFill}" />
|
<Setter Property="Margin" Value="0"/>
|
||||||
<Setter Property="BorderThickness" Value="{ThemeResource SliderBorderThemeThickness}" />
|
|
||||||
<Setter Property="Foreground" Value="{ThemeResource SliderTrackValueFill}" />
|
|
||||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
|
||||||
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
|
|
||||||
<Setter Property="ManipulationMode" Value="None" />
|
|
||||||
<Setter Property="UseSystemFocusVisuals" Value="True" />
|
|
||||||
<Setter Property="IsFocusEngagementEnabled" Value="True" />
|
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ControlTemplate TargetType="Slider">
|
<ControlTemplate TargetType="Slider">
|
||||||
<Grid Margin="{TemplateBinding Padding}">
|
<Grid>
|
||||||
<Grid.Resources>
|
<Grid.Resources>
|
||||||
<Style TargetType="Thumb" x:Key="SliderThumbStyle">
|
<Style TargetType="Thumb">
|
||||||
<Setter Property="BorderThickness" Value="0" />
|
<Setter Property="Background" Value="Red" />
|
||||||
<Setter Property="Background" Value="{ThemeResource SliderThumbBackground}" />
|
|
||||||
<Setter Property="Foreground" Value="{ThemeResource SystemControlBackgroundChromeMediumBrush}" />
|
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ControlTemplate TargetType="Thumb">
|
<ControlTemplate TargetType="Thumb">
|
||||||
<Ellipse x:Name="ellipse"
|
<Ellipse Fill="{TemplateBinding Background}"/>
|
||||||
Stroke="{TemplateBinding Background}"
|
|
||||||
StrokeThickness="2"
|
|
||||||
Fill="{TemplateBinding Foreground}" />
|
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
<Style TargetType="ProgressBar" x:Key="MediaSliderProgressBarStyle">
|
|
||||||
<Setter Property="Height" Value="{ThemeResource SliderTrackThemeHeight}" />
|
|
||||||
<Setter Property="Minimum" Value="0" />
|
|
||||||
<Setter Property="Maximum" Value="100" />
|
|
||||||
<Setter Property="Foreground" Value="{ThemeResource SystemControlHighlightChromeAltLowBrush}" />
|
|
||||||
<Setter Property="Background" Value="Transparent" />
|
|
||||||
<Setter Property="BorderBrush" Value="Transparent" />
|
|
||||||
<Setter Property="BorderThickness" Value="1" />
|
|
||||||
</Style>
|
|
||||||
</Grid.Resources>
|
</Grid.Resources>
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<VisualStateManager.VisualStateGroups>
|
<VisualStateManager.VisualStateGroups>
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
<VisualStateGroup x:Name="CommonStates">
|
||||||
<VisualState x:Name="Normal"/>
|
<VisualState x:Name="Normal"/>
|
||||||
@@ -91,61 +44,25 @@
|
|||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalTrackRect" Storyboard.TargetProperty="Fill">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalTrackRect" Storyboard.TargetProperty="Fill">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackFillPressed}" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackFillPressed}" />
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalTrackRect" Storyboard.TargetProperty="Fill">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackFillPressed}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalThumb" Storyboard.TargetProperty="Background">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalThumb" Storyboard.TargetProperty="Background">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderThumbBackgroundPressed}" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderThumbBackgroundPressed}" />
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalThumb" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderThumbBackgroundPressed}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SliderContainer" Storyboard.TargetProperty="Background">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SliderContainer" Storyboard.TargetProperty="Background">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderContainerBackgroundPressed}" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderContainerBackgroundPressed}" />
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalDecreaseRect" Storyboard.TargetProperty="Fill">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackValueFillPressed}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalDecreaseRect" Storyboard.TargetProperty="Fill">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackValueFillPressed}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</VisualState>
|
</VisualState>
|
||||||
<VisualState x:Name="Disabled">
|
<VisualState x:Name="Disabled">
|
||||||
<Storyboard>
|
<Storyboard>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HeaderContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderHeaderForegroundDisabled}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalDecreaseRect" Storyboard.TargetProperty="Fill">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalDecreaseRect" Storyboard.TargetProperty="Fill">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackValueFillDisabled}" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackValueFillDisabled}" />
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalTrackRect" Storyboard.TargetProperty="Fill">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalTrackRect" Storyboard.TargetProperty="Fill">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackFillDisabled}" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackFillDisabled}" />
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalDecreaseRect" Storyboard.TargetProperty="Fill">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackValueFillDisabled}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalTrackRect" Storyboard.TargetProperty="Fill">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackFillDisabled}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalThumb" Storyboard.TargetProperty="Background">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalThumb" Storyboard.TargetProperty="Background">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderThumbBackgroundDisabled}" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderThumbBackgroundDisabled}" />
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalThumb" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderThumbBackgroundDisabled}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TopTickBar" Storyboard.TargetProperty="Fill">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTickBarFillDisabled}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BottomTickBar" Storyboard.TargetProperty="Fill">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTickBarFillDisabled}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="LeftTickBar" Storyboard.TargetProperty="Fill">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTickBarFillDisabled}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RightTickBar" Storyboard.TargetProperty="Fill">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTickBarFillDisabled}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SliderContainer" Storyboard.TargetProperty="Background">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SliderContainer" Storyboard.TargetProperty="Background">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderContainerBackgroundDisabled}" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderContainerBackgroundDisabled}" />
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
@@ -156,24 +73,12 @@
|
|||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalTrackRect" Storyboard.TargetProperty="Fill">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalTrackRect" Storyboard.TargetProperty="Fill">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackFillPointerOver}" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackFillPointerOver}" />
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalTrackRect" Storyboard.TargetProperty="Fill">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackFillPointerOver}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalThumb" Storyboard.TargetProperty="Background">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalThumb" Storyboard.TargetProperty="Background">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderThumbBackgroundPointerOver}" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderThumbBackgroundPointerOver}" />
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalThumb" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderThumbBackgroundPointerOver}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SliderContainer" Storyboard.TargetProperty="Background">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SliderContainer" Storyboard.TargetProperty="Background">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderContainerBackgroundPointerOver}" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderContainerBackgroundPointerOver}" />
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalDecreaseRect" Storyboard.TargetProperty="Fill">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackValueFillPointerOver}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalDecreaseRect" Storyboard.TargetProperty="Fill">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SliderTrackValueFillPointerOver}" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</VisualState>
|
</VisualState>
|
||||||
</VisualStateGroup>
|
</VisualStateGroup>
|
||||||
@@ -189,156 +94,43 @@
|
|||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</VisualState>
|
</VisualState>
|
||||||
<VisualState x:Name="FocusEngagedVertical">
|
|
||||||
<Storyboard>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SliderContainer" Storyboard.TargetProperty="(Control.IsTemplateFocusTarget)">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="False" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalThumb" Storyboard.TargetProperty="(Control.IsTemplateFocusTarget)">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="True" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
</VisualStateGroup>
|
||||||
</VisualStateManager.VisualStateGroups>
|
</VisualStateManager.VisualStateGroups>
|
||||||
<ContentPresenter x:Name="HeaderContentPresenter"
|
|
||||||
x:DeferLoadStrategy="Lazy"
|
<Grid x:Name="SliderContainer" Control.IsTemplateFocusTarget="True" Background="{ThemeResource SliderContainerBackground}">
|
||||||
Visibility="Collapsed"
|
<Grid x:Name="HorizontalTemplate">
|
||||||
Foreground="{ThemeResource SliderHeaderForeground}"
|
|
||||||
Margin="{ThemeResource SliderHeaderThemeMargin}"
|
|
||||||
Content="{TemplateBinding Header}"
|
|
||||||
ContentTemplate="{TemplateBinding HeaderTemplate}"
|
|
||||||
FontWeight="{ThemeResource SliderHeaderThemeFontWeight}"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
<Grid x:Name="SliderContainer"
|
|
||||||
Background="{ThemeResource SliderContainerBackground}"
|
|
||||||
Grid.Row="1"
|
|
||||||
Control.IsTemplateFocusTarget="True">
|
|
||||||
<Grid x:Name="HorizontalTemplate" MinHeight="44">
|
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="15" />
|
<Rectangle x:Name="HorizontalTrackRect" Height="{StaticResource SliderTrackThemeHeight}" Fill="{TemplateBinding Background}" Grid.ColumnSpan="3"/>
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="15" />
|
<ProgressBar x:Name="DownloadProgressIndicator" Grid.ColumnSpan="3"
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Rectangle x:Name="HorizontalTrackRect"
|
|
||||||
Fill="{TemplateBinding Background}"
|
|
||||||
Height="{ThemeResource SliderTrackThemeHeight}"
|
Height="{ThemeResource SliderTrackThemeHeight}"
|
||||||
Grid.Row="1"
|
Foreground="{ThemeResource SystemControlHighlightChromeAltLowBrush}"
|
||||||
Grid.ColumnSpan="3" />
|
Background="Transparent"
|
||||||
<ProgressBar x:Name="DownloadProgressIndicator"
|
BorderBrush="Transparent"
|
||||||
Style="{StaticResource MediaSliderProgressBarStyle}"
|
BorderThickness="1"/>
|
||||||
Grid.Row="1"
|
|
||||||
Grid.ColumnSpan="3"
|
<Rectangle Height="4" x:Name="HorizontalDecreaseRect" Fill="{StaticResource SystemAccentColor}"/>
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Center" />
|
|
||||||
<Rectangle x:Name="HorizontalDecreaseRect" Fill="{TemplateBinding Foreground}" Grid.Row="1" />
|
|
||||||
<TickBar x:Name="TopTickBar"
|
|
||||||
Visibility="Collapsed"
|
|
||||||
Fill="{ThemeResource SliderTickBarFill}"
|
|
||||||
Height="{ThemeResource SliderOutsideTickBarThemeHeight}"
|
|
||||||
VerticalAlignment="Bottom"
|
|
||||||
Margin="0,0,0,4"
|
|
||||||
Grid.ColumnSpan="3" />
|
|
||||||
<TickBar x:Name="HorizontalInlineTickBar"
|
|
||||||
Visibility="Collapsed"
|
|
||||||
Fill="{ThemeResource SliderInlineTickBarFill}"
|
|
||||||
Height="{ThemeResource SliderTrackThemeHeight}"
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.ColumnSpan="3" />
|
|
||||||
<TickBar x:Name="BottomTickBar"
|
|
||||||
Visibility="Collapsed"
|
|
||||||
Fill="{ThemeResource SliderTickBarFill}"
|
|
||||||
Height="{ThemeResource SliderOutsideTickBarThemeHeight}"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
Margin="0,4,0,0"
|
|
||||||
Grid.Row="2"
|
|
||||||
Grid.ColumnSpan="3" />
|
|
||||||
<Thumb x:Name="HorizontalThumb"
|
<Thumb x:Name="HorizontalThumb"
|
||||||
Style="{StaticResource SliderThumbStyle}"
|
Height="15" Width="15" Grid.Column="1"
|
||||||
Height="15"
|
|
||||||
Width="15"
|
|
||||||
Grid.Row="0"
|
|
||||||
Grid.RowSpan="3"
|
|
||||||
Grid.Column="1"
|
|
||||||
AutomationProperties.AccessibilityView="Raw">
|
AutomationProperties.AccessibilityView="Raw">
|
||||||
<ToolTipService.ToolTip>
|
|
||||||
<ToolTip x:Name="ThumbnailTooltip">
|
|
||||||
<ContentPresenter Content="{Binding}" />
|
|
||||||
</ToolTip>
|
|
||||||
</ToolTipService.ToolTip>
|
|
||||||
<Thumb.DataContext>
|
<Thumb.DataContext>
|
||||||
<Grid Height="112" Width="192">
|
<Grid>
|
||||||
<Image x:Name="ThumbnailImage"/>
|
<Grid.RowDefinitions>
|
||||||
<Border Background="{ThemeResource SystemControlBackgroundBaseMediumBrush}"
|
<RowDefinition Height="112"/>
|
||||||
VerticalAlignment="Bottom"
|
<RowDefinition Height="Auto"/>
|
||||||
HorizontalAlignment="Left">
|
</Grid.RowDefinitions>
|
||||||
<TextBlock x:Name="TimeElapsedPreview"
|
<Image x:Name="ThumbnailImage" Width="192"/>
|
||||||
Margin="6,1,6,3"
|
<TextBlock Grid.Row="1" x:Name="TimeElapsedPreview"/>
|
||||||
Style="{StaticResource BodyTextBlockStyle}"
|
|
||||||
IsTextScaleFactorEnabled="False"
|
|
||||||
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}" />
|
|
||||||
</Border>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Thumb.DataContext>
|
</Thumb.DataContext>
|
||||||
</Thumb>
|
</Thumb>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid x:Name="VerticalTemplate" MinWidth="44" Visibility="Collapsed">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="18" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="18" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Rectangle x:Name="VerticalTrackRect"
|
|
||||||
Fill="{TemplateBinding Background}"
|
|
||||||
Width="{ThemeResource SliderTrackThemeHeight}"
|
|
||||||
Grid.Column="1"
|
|
||||||
Grid.RowSpan="3" />
|
|
||||||
<Rectangle x:Name="VerticalDecreaseRect"
|
|
||||||
Fill="{TemplateBinding Foreground}"
|
|
||||||
Grid.Column="1"
|
|
||||||
Grid.Row="2" />
|
|
||||||
<TickBar x:Name="LeftTickBar"
|
|
||||||
Visibility="Collapsed"
|
|
||||||
Fill="{ThemeResource SliderTickBarFill}"
|
|
||||||
Width="{ThemeResource SliderOutsideTickBarThemeHeight}"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Margin="0,0,4,0"
|
|
||||||
Grid.RowSpan="3" />
|
|
||||||
<TickBar x:Name="VerticalInlineTickBar"
|
|
||||||
Visibility="Collapsed"
|
|
||||||
Fill="{ThemeResource SliderInlineTickBarFill}"
|
|
||||||
Width="{ThemeResource SliderTrackThemeHeight}"
|
|
||||||
Grid.Column="1"
|
|
||||||
Grid.RowSpan="3" />
|
|
||||||
<TickBar x:Name="RightTickBar"
|
|
||||||
Visibility="Collapsed"
|
|
||||||
Fill="{ThemeResource SliderTickBarFill}"
|
|
||||||
Width="{ThemeResource SliderOutsideTickBarThemeHeight}"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Margin="4,0,0,0"
|
|
||||||
Grid.Column="2"
|
|
||||||
Grid.RowSpan="3" />
|
|
||||||
<Thumb x:Name="VerticalThumb"
|
|
||||||
Style="{StaticResource SliderThumbStyle}"
|
|
||||||
DataContext="{TemplateBinding Value}"
|
|
||||||
Width="24"
|
|
||||||
Height="8"
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="0"
|
|
||||||
Grid.ColumnSpan="3"
|
|
||||||
FocusVisualMargin="-6,-14,-6,-14"
|
|
||||||
AutomationProperties.AccessibilityView="Raw" />
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
@@ -348,7 +140,6 @@
|
|||||||
</Grid.Resources>
|
</Grid.Resources>
|
||||||
|
|
||||||
<VisualStateManager.VisualStateGroups>
|
<VisualStateManager.VisualStateGroups>
|
||||||
<!-- ControlPanel Visibility states -->
|
|
||||||
<VisualStateGroup x:Name="ControlPanelVisibilityStates">
|
<VisualStateGroup x:Name="ControlPanelVisibilityStates">
|
||||||
<VisualState x:Name="ControlPanelFadeIn">
|
<VisualState x:Name="ControlPanelFadeIn">
|
||||||
<Storyboard>
|
<Storyboard>
|
||||||
@@ -356,66 +147,34 @@
|
|||||||
<EasingDoubleKeyFrame KeyTime="0" Value="0" />
|
<EasingDoubleKeyFrame KeyTime="0" Value="0" />
|
||||||
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1" />
|
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1" />
|
||||||
</DoubleAnimationUsingKeyFrames>
|
</DoubleAnimationUsingKeyFrames>
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="center">
|
|
||||||
<EasingDoubleKeyFrame KeyTime="0" Value="0" />
|
|
||||||
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1" />
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="centerBgr">
|
|
||||||
<EasingDoubleKeyFrame KeyTime="0" Value="0" />
|
|
||||||
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1" />
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<DoubleAnimation Storyboard.TargetProperty="Y" Storyboard.TargetName="TranslateVerticalBottom" From="50" To ="0" Duration="0:0:0.3"/>
|
|
||||||
<DoubleAnimation Storyboard.TargetProperty="Y" Storyboard.TargetName="TranslateVerticalTop" From="-50" To ="0" Duration="0:0:0.3"/>
|
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</VisualState>
|
</VisualState>
|
||||||
<VisualState x:Name="ControlPanelFadeOut">
|
<VisualState x:Name="ControlPanelFadeOut">
|
||||||
<Storyboard>
|
<Storyboard>
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Border">
|
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Border">
|
||||||
<EasingDoubleKeyFrame KeyTime="0" Value="1" />
|
<EasingDoubleKeyFrame KeyTime="0" Value="1" />
|
||||||
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0" />
|
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="0" />
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="center">
|
|
||||||
<EasingDoubleKeyFrame KeyTime="0" Value="1" />
|
|
||||||
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0" />
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="centerBgr">
|
|
||||||
<EasingDoubleKeyFrame KeyTime="0" Value="1" />
|
|
||||||
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0" />
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
</DoubleAnimationUsingKeyFrames>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsHitTestVisible" Storyboard.TargetName="Border">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsHitTestVisible" Storyboard.TargetName="Border">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="False" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="False" />
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsHitTestVisible" Storyboard.TargetName="center">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="False" />
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<DoubleAnimation Storyboard.TargetProperty="Y" Storyboard.TargetName="TranslateVerticalBottom" From="0" To ="50" Duration="0:0:0.7"/>
|
|
||||||
<DoubleAnimation Storyboard.TargetProperty="Y" Storyboard.TargetName="TranslateVerticalTop" From="0" To ="-50" Duration="0:0:0.7"/>
|
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</VisualState>
|
</VisualState>
|
||||||
</VisualStateGroup>
|
</VisualStateGroup>
|
||||||
<!-- ControlPanel Visibility states -->
|
|
||||||
<!-- Media state visual states -->
|
|
||||||
<VisualStateGroup x:Name="MediaStates">
|
<VisualStateGroup x:Name="MediaStates">
|
||||||
<VisualState x:Name="Normal" />
|
<VisualState x:Name="Normal" />
|
||||||
<VisualState x:Name="Buffering">
|
<VisualState x:Name="Buffering">
|
||||||
<Storyboard>
|
<Storyboard>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="BufferingProgressBar">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="BufferingProgressBar">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0">
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
|
||||||
<DiscreteObjectKeyFrame.Value>
|
|
||||||
<Visibility>Visible</Visibility>
|
|
||||||
</DiscreteObjectKeyFrame.Value>
|
|
||||||
</DiscreteObjectKeyFrame>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</VisualState>
|
</VisualState>
|
||||||
<VisualState x:Name="Loading">
|
<VisualState x:Name="Loading">
|
||||||
<Storyboard>
|
<Storyboard>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="BufferingProgressBar">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="BufferingProgressBar">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0">
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
|
||||||
<DiscreteObjectKeyFrame.Value>
|
|
||||||
<Visibility>Visible</Visibility>
|
|
||||||
</DiscreteObjectKeyFrame.Value>
|
|
||||||
</DiscreteObjectKeyFrame>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<DoubleAnimation Storyboard.TargetName="ProgressSlider"
|
<DoubleAnimation Storyboard.TargetName="ProgressSlider"
|
||||||
Storyboard.TargetProperty="Opacity"
|
Storyboard.TargetProperty="Opacity"
|
||||||
@@ -439,24 +198,6 @@
|
|||||||
</VisualState>
|
</VisualState>
|
||||||
</VisualStateGroup>
|
</VisualStateGroup>
|
||||||
|
|
||||||
<!-- Focus states -->
|
|
||||||
<VisualStateGroup x:Name="FocusStates">
|
|
||||||
<VisualState x:Name="Focused">
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimation Storyboard.TargetName="FocusVisualWhite"
|
|
||||||
Storyboard.TargetProperty="Opacity"
|
|
||||||
To="1"
|
|
||||||
Duration="0" />
|
|
||||||
<DoubleAnimation Storyboard.TargetName="FocusVisualBlack"
|
|
||||||
Storyboard.TargetProperty="Opacity"
|
|
||||||
To="1"
|
|
||||||
Duration="0" />
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="Unfocused" />
|
|
||||||
<VisualState x:Name="PointerFocused" />
|
|
||||||
</VisualStateGroup>
|
|
||||||
|
|
||||||
<VisualStateGroup x:Name="PlayPauseStates">
|
<VisualStateGroup x:Name="PlayPauseStates">
|
||||||
<VisualState x:Name="PlayState" />
|
<VisualState x:Name="PlayState" />
|
||||||
<VisualState x:Name="PauseState">
|
<VisualState x:Name="PauseState">
|
||||||
@@ -467,7 +208,6 @@
|
|||||||
</Storyboard>
|
</Storyboard>
|
||||||
</VisualState>
|
</VisualState>
|
||||||
</VisualStateGroup>
|
</VisualStateGroup>
|
||||||
<!-- FullWindow states -->
|
|
||||||
<VisualStateGroup x:Name="FullWindowStates">
|
<VisualStateGroup x:Name="FullWindowStates">
|
||||||
<VisualState x:Name="NonFullWindowState" />
|
<VisualState x:Name="NonFullWindowState" />
|
||||||
<VisualState x:Name="FullWindowState">
|
<VisualState x:Name="FullWindowState">
|
||||||
@@ -481,161 +221,132 @@
|
|||||||
</VisualStateManager.VisualStateGroups>
|
</VisualStateManager.VisualStateGroups>
|
||||||
|
|
||||||
<Border x:Name="Border">
|
<Border x:Name="Border">
|
||||||
<Grid x:Name="ControlPanelGrid">
|
<Border.Resources>
|
||||||
<Grid.Resources>
|
|
||||||
<Style TargetType="Button" BasedOn="{StaticResource ButtonRevealStyle}">
|
<Style TargetType="Button" BasedOn="{StaticResource ButtonRevealStyle}">
|
||||||
<Setter Property="Width" Value="50"/>
|
<Setter Property="Width" Value="50"/>
|
||||||
<Setter Property="Height" Value="50"/>
|
<Setter Property="Height" Value="50"/>
|
||||||
|
<Setter Property="FontSize" Value="20"/>
|
||||||
<Setter Property="Background" Value="Transparent"/>
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="FontFamily" Value="Segoe UI, Segoe MDL2 Assets"/>
|
||||||
</Style>
|
</Style>
|
||||||
</Grid.Resources>
|
</Border.Resources>
|
||||||
|
<Grid x:Name="ControlPanelGrid">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
<RowDefinition Height="auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<Grid x:Name="header">
|
<Grid x:Name="header">
|
||||||
<Grid.RenderTransform>
|
|
||||||
<TranslateTransform x:Name="TranslateVerticalTop"/>
|
|
||||||
</Grid.RenderTransform>
|
|
||||||
|
|
||||||
<Grid.Background>
|
<Grid.Background>
|
||||||
<AcrylicBrush TintColor="#CC000000" TintOpacity=".6"/>
|
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
|
||||||
|
<GradientStop Color="Black"/>
|
||||||
|
<GradientStop Color="#00000000" Offset="1"/>
|
||||||
|
</LinearGradientBrush>
|
||||||
</Grid.Background>
|
</Grid.Background>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
<ColumnDefinition Width="auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<Button x:Name="minimize">
|
<Button x:Name="MinimizeButton" HorizontalAlignment="Left" VerticalAlignment="Top" Content=""/>
|
||||||
<FontIcon Glyph=""/>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<StackPanel Margin="10,0" Grid.Column="1" VerticalAlignment="Center">
|
<StackPanel VerticalAlignment="Top" Grid.Column="1" Margin="10,0">
|
||||||
<TextBlock x:Name="title" TextTrimming="CharacterEllipsis" FontSize="20" MaxLines="1"/>
|
<TextBlock x:Name="title" Text="Name" TextTrimming="CharacterEllipsis" MaxLines="1" Style="{StaticResource TitleTextBlockStyle}"/>
|
||||||
<TextBlock Foreground="LightGray" FontStyle="Italic" x:Name="author"/>
|
<TextBlock x:Name="channel" Text="Channel" TextTrimming="CharacterEllipsis" FontStyle="Italic"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal" Grid.Column="2" x:Name="headerToolbar">
|
<StackPanel x:Name="RightHeaderControls" Orientation="Horizontal" VerticalAlignment="Top" Grid.Column="2">
|
||||||
<Button x:Name="close">
|
<Button x:Name="CloseButton" HorizontalAlignment="Right" VerticalAlignment="Top" Content=""/>
|
||||||
<FontIcon Glyph=""/>
|
<Button x:Name="CastButton" Content=""/>
|
||||||
</Button>
|
<Button x:Name="CompactOverlayButton" HorizontalAlignment="Right" VerticalAlignment="Top" Content=""/>
|
||||||
<Button x:Name="CastButton">
|
|
||||||
<FontIcon Glyph=""/>
|
|
||||||
</Button>
|
|
||||||
<Button x:Name="CompactOverlayButton" VerticalAlignment="Top" HorizontalAlignment="Right">
|
|
||||||
<FontIcon Glyph=""/>
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid Grid.Row="1" x:Name="centerBgr" Visibility="Collapsed" IsHitTestVisible="False" Background="#66000000"/>
|
<Grid x:Name="center" Grid.Row="1" Visibility="Collapsed" Background="#7F000000">
|
||||||
<Grid Grid.Row="1" x:Name="center" Visibility="Collapsed">
|
<Button x:Name="drag" IsHitTestVisible="False" Height="32" Width="47" Margin="0,0,47,0" Content="" Visibility="Collapsed" Padding="0" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" VerticalAlignment="Top" HorizontalAlignment="Right"/>
|
||||||
<Button x:Name="maximize" VerticalAlignment="Top" HorizontalAlignment="Left" IsHitTestVisible="True">
|
<StackPanel x:Name="centerControls" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
<FontIcon Glyph=""/>
|
<ProgressBar x:Name="SeekIndicator" Background="Transparent" VerticalAlignment="Bottom"/>
|
||||||
</Button>
|
|
||||||
<Button x:Name="compactClose" VerticalAlignment="Top" HorizontalAlignment="Right">
|
|
||||||
<FontIcon Glyph=""/>
|
|
||||||
</Button>
|
|
||||||
<Button Height="32" Width="50" Margin="0,0,48,0" VerticalAlignment="Top" HorizontalAlignment="Right" Visibility="Collapsed" FontFamily="Segoe MDL2 Assets" Content="" IsHitTestVisible="False" x:Name="dragholder"/>
|
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center" x:Name="centralStack"/>
|
|
||||||
|
|
||||||
<ProgressBar VerticalAlignment="Bottom" x:Name="compactSeek" Background="Transparent"/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid Grid.Row="2" x:Name="footer">
|
<Grid x:Name="footer" Grid.Row="2">
|
||||||
<Grid.RenderTransform>
|
|
||||||
<TranslateTransform x:Name="TranslateVerticalBottom"/>
|
|
||||||
</Grid.RenderTransform>
|
|
||||||
|
|
||||||
<Grid.Background>
|
<Grid.Background>
|
||||||
<AcrylicBrush TintColor="#CC000000" TintOpacity=".6"/>
|
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
|
||||||
|
<GradientStop Color="Black" Offset="1"/>
|
||||||
|
<GradientStop Color="#00000000" Offset="0"/>
|
||||||
|
</LinearGradientBrush>
|
||||||
</Grid.Background>
|
</Grid.Background>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
<ColumnDefinition Width="auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal" x:Name="leftStack">
|
<ProgressBar x:Name="BufferingProgressBar" VerticalAlignment="Bottom" Grid.ColumnSpan="3" Background="Transparent" IsIndeterminate="True" Visibility="Collapsed"/>
|
||||||
|
|
||||||
|
<StackPanel x:Name="LeftFooterControls" Orientation="Horizontal" VerticalAlignment="Bottom">
|
||||||
<Button x:Name="PlayPauseButton">
|
<Button x:Name="PlayPauseButton">
|
||||||
<SymbolIcon x:Name="PlayPauseSymbol" Symbol="Play"/>
|
<SymbolIcon x:Name="PlayPauseSymbol" Symbol="Play"/>
|
||||||
</Button>
|
</Button>
|
||||||
<Button x:Name="next">
|
<Button x:Name="NextButton" Content=""/>
|
||||||
<SymbolIcon Symbol="Next"/>
|
<Button x:Name="VolumeMenuButton" Content="">
|
||||||
</Button>
|
|
||||||
<Button x:Name="volume">
|
|
||||||
<FontIcon Glyph=""/>
|
|
||||||
<Button.Flyout>
|
<Button.Flyout>
|
||||||
<Flyout>
|
<Flyout>
|
||||||
<StackPanel Orientation="Horizontal" Margin="-10">
|
<StackPanel Orientation="Horizontal" Margin="-10">
|
||||||
<Button x:Name="AudioMuteButton" Width="50" Height="50" Background="Transparent" FontFamily="Segoe MDL2 Assets" FontSize="25">
|
<Button x:Name="AudioMuteButton" Content="" FontFamily="Segoe MDL2 Assets" Height="50" Width="50" Background="Transparent" FontSize="20"/>
|
||||||
<FontIcon Glyph=""/>
|
<Slider x:Name="VolumeSlider" Width="150" Margin="10,5,10,0" VerticalAlignment="Center" TickPlacement="Outside" TickFrequency="10"/>
|
||||||
</Button>
|
|
||||||
<Slider Foreground="Red" Orientation="Horizontal" Width="150" Margin="10,5,10,0" VerticalAlignment="Center" x:Name="VolumeSlider"/>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Flyout>
|
</Flyout>
|
||||||
</Button.Flyout>
|
</Button.Flyout>
|
||||||
</Button>
|
</Button>
|
||||||
<Button x:Name="goLive" Width="NaN" Visibility="Collapsed">
|
<Button x:Name="PlayLiveButton" Width="NaN" Visibility="Collapsed">
|
||||||
<TextBlock x:Uid="/VideoPage/live" Text="🔴 LIVE"/>
|
<TextBlock x:Uid="/VideoPage/live" Text="🔴 LIVE"/>
|
||||||
</Button>
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<Grid Grid.Column="1" Margin="10,5" x:Name="sliderPan">
|
<Grid x:Name="CenterFooterControls" Height="50" Grid.Column="1" VerticalAlignment="Bottom">
|
||||||
<TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Left" x:Name="TimeElapsedElement" Text="00:00"/>
|
<Grid.RowDefinitions>
|
||||||
<TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Right" x:Name="TimeRemainingElement" Text="00:00"/>
|
<RowDefinition/>
|
||||||
<Grid VerticalAlignment="Top" Height="4" Margin="0,15,0,0">
|
<RowDefinition/>
|
||||||
<ProgressBar Background="#66FFFFFF" Foreground="#66FFFFFF" x:Name="BufferingProgressBar"/>
|
</Grid.RowDefinitions>
|
||||||
</Grid>
|
<TextBlock Grid.Row="1" Margin="5,0" VerticalAlignment="Center" HorizontalAlignment="Left" x:Name="TimeElapsedElement" Text="00:00"/>
|
||||||
<Slider x:Name="ProgressSlider" Style="{StaticResource PlayerSeek}" IsThumbToolTipEnabled="False" Background="Transparent" HorizontalAlignment="Stretch" VerticalAlignment="Top"/>
|
<TextBlock Grid.Row="1" Margin="5,0" VerticalAlignment="Center" HorizontalAlignment="Right" x:Name="TimeRemainingElement" Text="00:00"/>
|
||||||
|
<Slider x:Name="ProgressSlider" Style="{StaticResource PlayerSeek}" IsThumbToolTipEnabled="False" HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="5,0"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal" Grid.Column="2" x:Name="rightStack">
|
<StackPanel x:Name="RightFooterControls" Grid.Column="2" VerticalAlignment="Bottom" Orientation="Horizontal">
|
||||||
<Button x:Name="SkipBackwardButton">
|
<Button x:Name="SkipBackwardButton" Content=""/>
|
||||||
<FontIcon Glyph=""/>
|
<Button x:Name="SkipForwardButton" Content=""/>
|
||||||
</Button>
|
|
||||||
<Button x:Name="SkipForwardButton">
|
|
||||||
<FontIcon Glyph=""/>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Line Stroke="White" StrokeThickness="2" Y1="5" Y2="45"/>
|
<Line Stroke="White" StrokeThickness="2" Y1="5" Y2="45"/>
|
||||||
|
<Button x:Name="CaptionsMenuButton" Content="">
|
||||||
<Button x:Name="cc">
|
|
||||||
<SymbolIcon Symbol="ClosedCaption"/>
|
|
||||||
<Button.Flyout>
|
<Button.Flyout>
|
||||||
<Flyout>
|
<Flyout>
|
||||||
<StackPanel Width="225">
|
<StackPanel Width="225">
|
||||||
<ToggleSwitch x:Name="ccSwitch" OnContent="Subtitles" OffContent="Subtitles" x:Uid="/VideoPage/subsSwitch"/>
|
<ToggleSwitch x:Name="CaptionsToggleSwitch" OnContent="Subtitles" OffContent="Subtitles" x:Uid="/VideoPage/subsSwitch"/>
|
||||||
<ComboBox x:Name="ccSelector" Header="Language" x:Uid="/VideoPage/subsSelector" PlaceholderText="No subtitles are available" HorizontalAlignment="Stretch"/>
|
<ComboBox x:Name="CaptionsSelector" Header="Language" x:Uid="/VideoPage/subsSelector" PlaceholderText="No captions are available" HorizontalAlignment="Stretch"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Flyout>
|
</Flyout>
|
||||||
</Button.Flyout>
|
</Button.Flyout>
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button x:Name="QualityMenuButton" Content="">
|
||||||
<Button x:Name="quality">
|
|
||||||
<SymbolIcon Symbol="Setting"/>
|
|
||||||
<Button.Flyout>
|
<Button.Flyout>
|
||||||
<Flyout>
|
<Flyout>
|
||||||
<ComboBox Width="225" x:Uid="/VideoPage/qualitySelector" Header="Quality" x:Name="qualitySelector"/>
|
<ComboBox Width="225" x:Name="QualitySelector" Header="Language" x:Uid="/VideoPage/qualitySelector"/>
|
||||||
</Flyout>
|
</Flyout>
|
||||||
</Button.Flyout>
|
</Button.Flyout>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button x:Name="FullWindowButton">
|
<Button x:Name="FullWindowButton">
|
||||||
<SymbolIcon x:Name="FullWindowSymbol" Symbol="FullScreen"/>
|
<SymbolIcon x:Name="FullWindowSymbol" Symbol="FullScreen"/>
|
||||||
</Button>
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
<controls:LiveCaptions Visibility="Collapsed" x:Name="captions"/>
|
|
||||||
|
|
||||||
<adverts:PlayerAdvert Grid.Row="1" x:Name="ad" VerticalAlignment="Bottom"/>
|
<controls:LiveCaptions Visibility="Collapsed" x:Name="CaptionControl"/>
|
||||||
|
|
||||||
|
<adverts:PlayerAdvert Grid.Row="1" x:Name="AdvertControl" VerticalAlignment="Bottom"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
|
|||||||