This commit is contained in:
2024-02-28 01:22:13 +01:00
Unverified
parent e3ec5c3a48
commit 74eb899e31
51 changed files with 562 additions and 608 deletions

View File

@@ -9,8 +9,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.230913002" /> <PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.240211001" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.755" /> <PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -140,7 +140,7 @@ namespace VDownload.Core.Tasks
await _settingsService.Load(); await _settingsService.Load();
string tempDirectory = $"{_settingsService.Data.Common.TempDirectory}\\{_configurationService.Common.Path.Temp.TasksDirectory}\\{_id}"; string tempDirectory = $"{_settingsService.Data.Common.Temp.Directory}\\{_configurationService.Common.Path.Temp.TasksDirectory}\\{_id}";
Directory.CreateDirectory(tempDirectory); Directory.CreateDirectory(tempDirectory);
List<string> content = new List<string>() List<string> content = new List<string>()
@@ -211,7 +211,7 @@ namespace VDownload.Core.Tasks
} }
finally finally
{ {
if (Status != DownloadTaskStatus.EndedUnsuccessfully || _settingsService.Data.Common.DeleteTempOnError) if (Status != DownloadTaskStatus.EndedUnsuccessfully || _settingsService.Data.Common.Temp.DeleteOnError)
{ {
Directory.Delete(tempDirectory, true); Directory.Delete(tempDirectory, true);
} }

View File

@@ -129,13 +129,12 @@ namespace VDownload.Core.Tasks
DownloadTaskStatus.Processing, DownloadTaskStatus.Processing,
DownloadTaskStatus.Finalizing DownloadTaskStatus.Finalizing
]; ];
while (true) while (true)
{ {
try try
{ {
IEnumerable<DownloadTask> pendingTasks = Tasks.Where(x => pendingStatuses.Contains(x.Status)); IEnumerable<DownloadTask> pendingTasks = Tasks.Where(x => pendingStatuses.Contains(x.Status));
int freeSlots = _settingsService.Data.Common.MaxNumberOfRunningTasks - pendingTasks.Count(); int freeSlots = _settingsService.Data.Common.Tasks.MaxNumberOfRunningTasks - pendingTasks.Count();
if (freeSlots > 0) if (freeSlots > 0)
{ {
IEnumerable<DownloadTask> queuedTasks = Tasks.Where(x => x.Status == DownloadTaskStatus.Queued).OrderBy(x => x.CreateDate).Take(freeSlots); IEnumerable<DownloadTask> queuedTasks = Tasks.Where(x => x.Status == DownloadTaskStatus.Queued).OrderBy(x => x.CreateDate).Take(freeSlots);

View File

@@ -11,7 +11,7 @@ using VDownload.Core.ViewModels.Home;
using VDownload.Core.ViewModels.Settings; using VDownload.Core.ViewModels.Settings;
using VDownload.Services.UI.DictionaryResources; using VDownload.Services.UI.DictionaryResources;
using VDownload.Services.UI.StringResources; using VDownload.Services.UI.StringResources;
using VDownload.Toolkit.UI.Models; using SimpleToolkit.UI.Models;
namespace VDownload.Core.ViewModels namespace VDownload.Core.ViewModels
{ {

View File

@@ -0,0 +1,75 @@
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VDownload.Models;
using VDownload.Sources.Twitch.Configuration.Models;
namespace VDownload.Core.ViewModels.Home
{
public partial class HomePlaylistViewModel : ObservableObject
{
#region SERVICES
#endregion
#region FIELDS
#endregion
#region PROPERTIES
[ObservableProperty]
protected string _name;
#endregion
#region CONSTRUCTORS
public HomePlaylistViewModel()
{
}
#endregion
#region PUBLIC METHODS
public async Task LoadPlaylist(Playlist playlist)
{
Name = playlist.Name;
}
#endregion
#region COMMANDS
#endregion
#region EVENTS
public event EventHandler CloseRequested;
#endregion
}
}

View File

@@ -87,14 +87,6 @@ namespace VDownload.Core.ViewModels.Home
#region EVENTS
public event EventHandler TaskAdded;
#endregion
#region CONSTRUCTORS #region CONSTRUCTORS
public HomeVideoViewModel(IDownloadTaskManager tasksManager, ISettingsService settingsService, IStoragePickerService storagePickerService) public HomeVideoViewModel(IDownloadTaskManager tasksManager, ISettingsService settingsService, IStoragePickerService storagePickerService)
@@ -110,7 +102,7 @@ namespace VDownload.Core.ViewModels.Home
#region PUBLIC METHODS #region PUBLIC METHODS
public async void LoadVideo(Video video) public async Task LoadVideo(Video video)
{ {
await _settingsService.Load(); await _settingsService.Load();
@@ -125,13 +117,13 @@ namespace VDownload.Core.ViewModels.Home
Streams = [.. video.Streams]; Streams = [.. video.Streams];
SelectedStream = Streams[0]; SelectedStream = Streams[0];
MediaType = _settingsService.Data.Common.DefaultTaskSettings.MediaType; MediaType = _settingsService.Data.Common.Tasks.DefaultMediaType;
TrimStart = TimeSpan.Zero; TrimStart = TimeSpan.Zero;
TrimEnd = Duration; TrimEnd = Duration;
DirectoryPath = _settingsService.Data.Common.DefaultTaskSettings.OutputDirectory; DirectoryPath = _settingsService.Data.Common.Tasks.DefaultOutputDirectory;
Filename = Title.Length > 50 ? Title.Substring(0, 50) : Title; Filename = Title.Length > 50 ? Title.Substring(0, 50) : Title;
VideoExtension = _settingsService.Data.Common.DefaultTaskSettings.VideoExtension; VideoExtension = _settingsService.Data.Common.Tasks.DefaultVideoExtension;
AudioExtension = _settingsService.Data.Common.DefaultTaskSettings.AudioExtension; AudioExtension = _settingsService.Data.Common.Tasks.DefaultAudioExtension;
} }
@@ -149,14 +141,14 @@ namespace VDownload.Core.ViewModels.Home
public void CreateTask() public void CreateTask()
{ {
_tasksManager.AddTask(_video, BuildDownloadOptions()); _tasksManager.AddTask(_video, BuildDownloadOptions());
TaskAdded?.Invoke(this, EventArgs.Empty); CloseRequested?.Invoke(this, EventArgs.Empty);
} }
[RelayCommand] [RelayCommand]
public void CreateTaskAndDownload() public void CreateTaskAndDownload()
{ {
DownloadTask task = _tasksManager.AddTask(_video, BuildDownloadOptions()); DownloadTask task = _tasksManager.AddTask(_video, BuildDownloadOptions());
TaskAdded?.Invoke(this, EventArgs.Empty); CloseRequested?.Invoke(this, EventArgs.Empty);
task.Enqueue(); task.Enqueue();
} }
@@ -181,5 +173,13 @@ namespace VDownload.Core.ViewModels.Home
} }
#endregion #endregion
#region EVENTS
public event EventHandler CloseRequested;
#endregion
} }
} }

View File

@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using VDownload.Core.Tasks;
using VDownload.Models; using VDownload.Models;
using VDownload.Services.Data.Configuration; using VDownload.Services.Data.Configuration;
using VDownload.Services.Data.Settings; using VDownload.Services.Data.Settings;
@@ -42,7 +43,10 @@ namespace VDownload.Core.ViewModels.Home
protected readonly IStringResourcesService _stringResourcesService; protected readonly IStringResourcesService _stringResourcesService;
protected readonly ISearchService _searchService; protected readonly ISearchService _searchService;
protected readonly IDownloadTaskManager _downloadTaskManager;
protected readonly HomeVideoViewModel _videoViewModel; protected readonly HomeVideoViewModel _videoViewModel;
protected readonly HomePlaylistViewModel _playlistViewModel;
#endregion #endregion
@@ -52,6 +56,7 @@ namespace VDownload.Core.ViewModels.Home
protected readonly Type _downloadsView = typeof(HomeDownloadsViewModel); protected readonly Type _downloadsView = typeof(HomeDownloadsViewModel);
protected readonly Type _videoView = typeof(HomeVideoViewModel); protected readonly Type _videoView = typeof(HomeVideoViewModel);
protected readonly Type _playlistView = typeof(HomePlaylistViewModel);
#endregion #endregion
@@ -96,15 +101,20 @@ namespace VDownload.Core.ViewModels.Home
#region CONSTRUCTORS #region CONSTRUCTORS
public HomeViewModel(IConfigurationService configurationService, ISettingsService settingsService, IStringResourcesService stringResourcesService, ISearchService searchService, HomeVideoViewModel videoViewModel) public HomeViewModel(IConfigurationService configurationService, ISettingsService settingsService, IStringResourcesService stringResourcesService, ISearchService searchService, IDownloadTaskManager downloadTaskManager, HomeVideoViewModel videoViewModel, HomePlaylistViewModel playlistViewModel)
{ {
_configurationService = configurationService; _configurationService = configurationService;
_settingsService = settingsService; _settingsService = settingsService;
_stringResourcesService = stringResourcesService; _stringResourcesService = stringResourcesService;
_searchService = searchService; _searchService = searchService;
_downloadTaskManager = downloadTaskManager;
_videoViewModel = videoViewModel; _videoViewModel = videoViewModel;
_videoViewModel.TaskAdded += VideoViewModel_TaskAdded; _videoViewModel.CloseRequested += BackToDownload_EventHandler;
_playlistViewModel = playlistViewModel;
_playlistViewModel.CloseRequested += BackToDownload_EventHandler;
} }
#endregion #endregion
@@ -195,7 +205,7 @@ namespace VDownload.Core.ViewModels.Home
return; return;
} }
_videoViewModel.LoadVideo(video); await _videoViewModel.LoadVideo(video);
MainContent = _videoView; MainContent = _videoView;
@@ -224,6 +234,10 @@ namespace VDownload.Core.ViewModels.Home
return; return;
} }
await _playlistViewModel.LoadPlaylist(playlist);
MainContent = _playlistView;
OptionBarSearchNotPending = true; OptionBarSearchNotPending = true;
OptionBarLoading = false; OptionBarLoading = false;
OptionBarMessage = null; OptionBarMessage = null;
@@ -232,7 +246,10 @@ namespace VDownload.Core.ViewModels.Home
[RelayCommand] [RelayCommand]
public void Download() public void Download()
{ {
foreach (DownloadTask task in _downloadTaskManager.Tasks)
{
task.Enqueue();
}
} }
#endregion #endregion
@@ -241,7 +258,7 @@ namespace VDownload.Core.ViewModels.Home
#region PRIVATE METHODS #region PRIVATE METHODS
private async void VideoViewModel_TaskAdded(object sender, EventArgs e) => await Navigation(); private async void BackToDownload_EventHandler(object sender, EventArgs e) => await Navigation();
#endregion #endregion
} }

View File

@@ -12,6 +12,7 @@
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.240211001" /> <PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.240211001" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" /> <PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" /> <PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="SimpleToolkit.UI.Models" Version="1.4.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -23,7 +24,6 @@
<ProjectReference Include="..\..\VDownload.Services\VDownload.Services.UI\VDownload.Services.UI.WebView\VDownload.Services.UI.WebView.csproj" /> <ProjectReference Include="..\..\VDownload.Services\VDownload.Services.UI\VDownload.Services.UI.WebView\VDownload.Services.UI.WebView.csproj" />
<ProjectReference Include="..\..\VDownload.Sources\VDownload.Sources.Twitch\VDownload.Sources.Twitch.Authentication\VDownload.Sources.Twitch.Authentication.csproj" /> <ProjectReference Include="..\..\VDownload.Sources\VDownload.Sources.Twitch\VDownload.Sources.Twitch.Authentication\VDownload.Sources.Twitch.Authentication.csproj" />
<ProjectReference Include="..\..\VDownload.Sources\VDownload.Sources\VDownload.Sources.csproj" /> <ProjectReference Include="..\..\VDownload.Sources\VDownload.Sources\VDownload.Sources.csproj" />
<ProjectReference Include="..\..\VDownload.Toolkit\VDownload.Toolkit.UI\VDownload.Toolkit.UI.Models\VDownload.Toolkit.UI.Models.csproj" />
<ProjectReference Include="..\VDownload.Core.Tasks\VDownload.Core.Tasks.csproj" /> <ProjectReference Include="..\VDownload.Core.Tasks\VDownload.Core.Tasks.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -7,7 +7,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="using:Microsoft.Xaml.Interactivity" xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:ic="using:Microsoft.Xaml.Interactions.Core" xmlns:ic="using:Microsoft.Xaml.Interactions.Core"
xmlns:cb="using:VDownload.Toolkit.UI.Behaviors" xmlns:cb="using:SimpleToolkit.UI.WinUI.Behaviors"
mc:Ignorable="d"> mc:Ignorable="d">
<Window.SystemBackdrop> <Window.SystemBackdrop>
<MicaBackdrop Kind="Base"/> <MicaBackdrop Kind="Base"/>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<Page
x:Class="VDownload.Core.Views.Home.HomePlaylistView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:VDownload.Core.Views.Home"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ViewBackgroundColor}">
<Grid Padding="15"
RowSpacing="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{Binding Name}"
FontWeight="Bold"
FontSize="20"
TextWrapping="WrapWholeWords"/>
<AppBarButton Grid.Column="2"
Margin="-5"
Icon="Filter"
Width="40"
Height="48">
<AppBarButton.Resources>
<TeachingTip x:Name="FilterWindow">
</TeachingTip>
</AppBarButton.Resources>
</AppBarButton>
</Grid>
<ItemsControl Grid.Row="1">
</ItemsControl>
<StackPanel Grid.Row="2"
HorizontalAlignment="Right"
Orientation="Horizontal">
</StackPanel>
</Grid>
</Page>

View File

@@ -0,0 +1,31 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using VDownload.Core.ViewModels.Home;
using Windows.Foundation;
using Windows.Foundation.Collections;
namespace VDownload.Core.Views.Home
{
public sealed partial class HomePlaylistView : Page
{
#region CONSTRUCTORS
public HomePlaylistView(HomePlaylistViewModel viewModel)
{
this.InitializeComponent();
this.DataContext = viewModel;
}
#endregion
}
}

View File

@@ -12,7 +12,7 @@
xmlns:ct="using:CommunityToolkit.WinUI" xmlns:ct="using:CommunityToolkit.WinUI"
xmlns:ctc="using:CommunityToolkit.WinUI.Controls" xmlns:ctc="using:CommunityToolkit.WinUI.Controls"
xmlns:ctuc="using:CommunityToolkit.WinUI.UI.Controls" xmlns:ctuc="using:CommunityToolkit.WinUI.UI.Controls"
xmlns:c="using:VDownload.Toolkit.UI.Controls" xmlns:c="using:SimpleToolkit.UI.WinUI.Controls"
mc:Ignorable="d" mc:Ignorable="d"
Background="{ThemeResource ViewBackgroundColor}"> Background="{ThemeResource ViewBackgroundColor}">

View File

@@ -7,6 +7,9 @@
<UseWinUI>true</UseWinUI> <UseWinUI>true</UseWinUI>
<UseRidGraph>true</UseRidGraph> <UseRidGraph>true</UseRidGraph>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<None Remove="Home\HomePlaylistView.xaml" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CommunityToolkit.WinUI" Version="7.1.2" /> <PackageReference Include="CommunityToolkit.WinUI" Version="7.1.2" />
@@ -16,11 +19,11 @@
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.240211001" /> <PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.240211001" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" /> <PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" /> <PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
<PackageReference Include="SimpleToolkit.UI.WinUI.Behaviors" Version="1.4.0" />
<PackageReference Include="SimpleToolkit.UI.WinUI.Controls" Version="1.4.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\VDownload.Toolkit\VDownload.Toolkit.UI\VDownload.Toolkit.UI.Behaviors\VDownload.Toolkit.UI.Behaviors.csproj" />
<ProjectReference Include="..\..\VDownload.Toolkit\VDownload.Toolkit.UI\VDownload.Toolkit.UI.Controls\VDownload.Toolkit.UI.Controls.csproj" />
<ProjectReference Include="..\VDownload.Core.Strings\VDownload.Core.Strings.csproj" /> <ProjectReference Include="..\VDownload.Core.Strings\VDownload.Core.Strings.csproj" />
<ProjectReference Include="..\VDownload.Core.ViewModels\VDownload.Core.ViewModels.csproj" /> <ProjectReference Include="..\VDownload.Core.ViewModels\VDownload.Core.ViewModels.csproj" />
</ItemGroup> </ItemGroup>
@@ -35,6 +38,9 @@
<None Update="Home\HomeDownloadsView.xaml"> <None Update="Home\HomeDownloadsView.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</None> </None>
<Page Update="Home\HomePlaylistView.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<None Update="Home\HomeVideoView.xaml"> <None Update="Home\HomeVideoView.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</None> </None>

View File

@@ -20,6 +20,7 @@ namespace VDownload.Core.Views
{ typeof(HomeViewModel), typeof(HomeView) }, { typeof(HomeViewModel), typeof(HomeView) },
{ typeof(HomeDownloadsViewModel), typeof(HomeDownloadsView) }, { typeof(HomeDownloadsViewModel), typeof(HomeDownloadsView) },
{ typeof(HomeVideoViewModel), typeof(HomeVideoView) }, { typeof(HomeVideoViewModel), typeof(HomeVideoView) },
{ typeof(HomePlaylistViewModel), typeof(HomePlaylistView) },
{ typeof(SettingsViewModel), typeof(SettingsView) }, { typeof(SettingsViewModel), typeof(SettingsView) },
{ typeof(AuthenticationViewModel), typeof(AuthenticationView) } { typeof(AuthenticationViewModel), typeof(AuthenticationView) }
}; };

View File

@@ -6,7 +6,15 @@ using System.Threading.Tasks;
namespace VDownload.Models namespace VDownload.Models
{ {
public abstract class Playlist public abstract class Playlist : List<Video>
{ {
#region PROPERTIES
public required string Name { get; set; }
public required string Description { get; set; }
public required Uri Url { get; set; }
public Source Source { get; protected set; }
#endregion
} }
} }

View File

@@ -17,9 +17,9 @@ namespace VDownload.Models
public TimeSpan Duration { get; set; } public TimeSpan Duration { get; set; }
public long Views { get; set; } public long Views { get; set; }
public Uri ThumbnailUrl { get; set; } public Uri ThumbnailUrl { get; set; }
public ICollection<VideoStream> Streams { get; set; }
public Uri Url { get; set; } public Uri Url { get; set; }
public Source Source { get; set; } public ICollection<VideoStream> Streams { get; private set; }
public Source Source { get; protected set; }
#endregion #endregion

View File

@@ -15,17 +15,11 @@ namespace VDownload.Services.Data.Settings
[JsonProperty("max_number_of_videos_to_get_from_playlist")] [JsonProperty("max_number_of_videos_to_get_from_playlist")]
public int MaxNumberOfVideosToGetFromPlaylist { get; set; } = 0; public int MaxNumberOfVideosToGetFromPlaylist { get; set; } = 0;
[JsonProperty("max_number_of_running_tasks")] [JsonProperty("temp")]
public int MaxNumberOfRunningTasks { get; set; } = 5; public Temp Temp { get; set; } = new Temp();
[JsonProperty("temp_directory")] [JsonProperty("tasks")]
public string TempDirectory { get; set; } = $"{Path.GetTempPath()}\\VDownload"; public Tasks Tasks { get; set; } = new Tasks();
[JsonProperty("delete_temp_on_error")]
public bool DeleteTempOnError { get; set; } = true;
[JsonProperty("default_task_settings")]
public DefaultTaskSettings DefaultTaskSettings { get; set; } = new DefaultTaskSettings();
[JsonProperty("notifications")] [JsonProperty("notifications")]
public Notifications Notifications { get; set; } = new Notifications(); public Notifications Notifications { get; set; } = new Notifications();

View File

@@ -1,28 +0,0 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VDownload.Models;
namespace VDownload.Services.Data.Settings.Models
{
public class DefaultTaskSettings
{
[JsonProperty("media_type")]
public MediaType MediaType { get; set; } = MediaType.Original;
[JsonProperty("video_extension")]
public VideoExtension VideoExtension { get; set; } = VideoExtension.MP4;
[JsonProperty("audio_extension")]
public AudioExtension AudioExtension { get; set; } = AudioExtension.MP3;
[JsonProperty("output_directory")]
public string OutputDirectory { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
[JsonProperty("save_last_output_directory")]
public bool SaveLastOutputDirectory { get; set; } = false;
}
}

View File

@@ -0,0 +1,31 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VDownload.Models;
namespace VDownload.Services.Data.Settings.Models
{
public class Tasks
{
[JsonProperty("default_media_type")]
public MediaType DefaultMediaType { get; set; } = MediaType.Original;
[JsonProperty("default_video_extension")]
public VideoExtension DefaultVideoExtension { get; set; } = VideoExtension.MP4;
[JsonProperty("default_audio_extension")]
public AudioExtension DefaultAudioExtension { get; set; } = AudioExtension.MP3;
[JsonProperty("default_output_directory")]
public string DefaultOutputDirectory { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
[JsonProperty("save_last_output_directory")]
public bool SaveLastOutputDirectory { get; set; } = false;
[JsonProperty("max_number_of_running_tasks")]
public int MaxNumberOfRunningTasks { get; set; } = 5;
}
}

View File

@@ -0,0 +1,18 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VDownload.Services.Data.Settings.Models
{
public class Temp
{
[JsonProperty("directory")]
public string Directory { get; set; } = $"{Path.GetTempPath()}\\VDownload";
[JsonProperty("delete_on_error")]
public bool DeleteOnError { get; set; } = true;
}
}

View File

@@ -75,15 +75,15 @@ namespace VDownload.Services.Data.Settings
public async Task Load() public async Task Load()
{ {
Data = null;
if (File.Exists(_filePath)) if (File.Exists(_filePath))
{ {
string content = await File.ReadAllTextAsync(_filePath); string content = await File.ReadAllTextAsync(_filePath);
Data = JsonConvert.DeserializeObject<SettingsData>(content); Data = JsonConvert.DeserializeObject<SettingsData>(content);
} }
else
Data ??= new SettingsData(); {
Data = new SettingsData();
}
} }
public async Task Save() public async Task Save()

View File

@@ -9,7 +9,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.230913002" /> <PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.240211001" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.755" /> <PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -9,8 +9,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.230913002" /> <PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.240211001" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.755" /> <PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -86,7 +86,9 @@ namespace VDownload.Services.Utility.HttpClient
HttpResponseMessage response = await _httpClient.SendAsync(httpRequest); HttpResponseMessage response = await _httpClient.SendAsync(httpRequest);
return await response.Content.ReadAsStringAsync(); string responseString = await response.Content.ReadAsStringAsync();
return responseString;
} }
#endregion #endregion

View File

@@ -0,0 +1,45 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VDownload.Sources.Twitch.Api.Helix.GetUsers.Response
{
public class Data
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("login")]
public string Login { get; set; }
[JsonProperty("display_name")]
public string DisplayName { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("broadcaster_type")]
public string BroadcasterType { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("profile_image_url")]
public string ProfileImageUrl { get; set; }
[JsonProperty("offline_image_url")]
public string OfflineImageUrl { get; set; }
[JsonProperty("view_count")]
public int ViewCount { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("created_at")]
public DateTime CreatedAt { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VDownload.Sources.Twitch.Api.Helix.GetUsers.Response
{
public class GetUsersResponse
{
[JsonProperty("data")]
public List<Data> Data { get; } = new List<Data>();
}
}

View File

@@ -1,6 +1,7 @@
using VDownload.Services.Data.Configuration; using VDownload.Services.Data.Configuration;
using VDownload.Services.Utility.HttpClient; using VDownload.Services.Utility.HttpClient;
using VDownload.Sources.Twitch.Api.GQL.GetVideoToken.Response; using VDownload.Sources.Twitch.Api.GQL.GetVideoToken.Response;
using VDownload.Sources.Twitch.Api.Helix.GetUsers.Response;
using VDownload.Sources.Twitch.Api.Helix.GetVideos.Response; using VDownload.Sources.Twitch.Api.Helix.GetVideos.Response;
using VDownload.Sources.Twitch.Search.Models.GetVideoToken.Request; using VDownload.Sources.Twitch.Search.Models.GetVideoToken.Request;
@@ -10,7 +11,9 @@ namespace VDownload.Sources.Twitch.Api
{ {
Task<string> AuthValidate(byte[] token); Task<string> AuthValidate(byte[] token);
Task<GetVideoTokenResponse> GQLGetVideoToken(string id); Task<GetVideoTokenResponse> GQLGetVideoToken(string id);
Task<GetVideosResponse> HelixGetVideos(string id, byte[] token); Task<GetUsersResponse> HelixGetUser(string login, byte[] token);
Task<GetVideosResponse> HelixGetVideo(string id, byte[] token);
Task<GetVideosResponse> HelixGetUserVideos(string user_id, byte[] token, int count, string? cursor = null);
Task<string> UsherGetVideoPlaylist(string id, string videoToken, string videoTokenSignature); Task<string> UsherGetVideoPlaylist(string id, string videoToken, string videoTokenSignature);
} }
@@ -49,12 +52,47 @@ namespace VDownload.Sources.Twitch.Api
return await _httpClientService.SendRequestAsync(request); return await _httpClientService.SendRequestAsync(request);
} }
public async Task<GetVideosResponse> HelixGetVideos(string id, byte[] token) public async Task<GetUsersResponse> HelixGetUser(string login, byte[] token)
{
Token tokenData = new Token(_configurationService.Twitch.Api.Helix.TokenSchema, token);
HttpRequest request = new HttpRequest(HttpMethodType.GET, _configurationService.Twitch.Api.Helix.Endpoints.GetUsers);
request.Query.Add("login", login);
request.Headers.Add("Authorization", $"{tokenData}");
request.Headers.Add("Client-Id", _configurationService.Twitch.Api.Helix.ClientId);
return await _httpClientService.SendRequestAsync<GetUsersResponse>(request);
}
public async Task<GetVideosResponse> HelixGetVideo(string id, byte[] token)
{ {
Token tokenData = new Token(_configurationService.Twitch.Api.Helix.TokenSchema, token); Token tokenData = new Token(_configurationService.Twitch.Api.Helix.TokenSchema, token);
HttpRequest request = new HttpRequest(HttpMethodType.GET, _configurationService.Twitch.Api.Helix.Endpoints.GetVideos); HttpRequest request = new HttpRequest(HttpMethodType.GET, _configurationService.Twitch.Api.Helix.Endpoints.GetVideos);
request.Query.Add("id", id); request.Query.Add("id", id);
request.Headers.Add("Authorization", tokenData.ToString());
request.Headers.Add("Client-Id", _configurationService.Twitch.Api.Helix.ClientId);
return await _httpClientService.SendRequestAsync<GetVideosResponse>(request);
}
public async Task<GetVideosResponse> HelixGetUserVideos(string user_id, byte[] token, int count, string? cursor = null)
{
Token tokenData = new Token(_configurationService.Twitch.Api.Helix.TokenSchema, token);
HttpRequest request = new HttpRequest(HttpMethodType.GET, _configurationService.Twitch.Api.Helix.Endpoints.GetVideos);
request.Query.Add("user_id", user_id);
request.Query.Add("first", count);
if (cursor is not null)
{
request.Query.Add("after", cursor);
}
request.Headers.Add("Authorization", tokenData.ToString()); request.Headers.Add("Authorization", tokenData.ToString());
request.Headers.Add("Client-Id", _configurationService.Twitch.Api.Helix.ClientId); request.Headers.Add("Client-Id", _configurationService.Twitch.Api.Helix.ClientId);

View File

@@ -0,0 +1,18 @@
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VDownload.Sources.Twitch.Configuration.Models
{
public class Channel
{
[ConfigurationKeyName("regexes")]
public List<string> Regexes { get; } = new List<string>();
[ConfigurationKeyName("url")]
public string Url { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VDownload.Sources.Twitch.Configuration.Models
{
public class Clip
{
[ConfigurationKeyName("regexes")]
public List<string> Regexes { get; } = new List<string>();
}
}

View File

@@ -6,5 +6,8 @@ namespace VDownload.Sources.Twitch.Configuration.Models
{ {
[ConfigurationKeyName("get_videos")] [ConfigurationKeyName("get_videos")]
public string GetVideos { get; set; } public string GetVideos { get; set; }
[ConfigurationKeyName("get_users")]
public string GetUsers { get; set; }
} }
} }

View File

@@ -8,6 +8,12 @@ namespace VDownload.Sources.Twitch.Configuration.Models{
[ConfigurationKeyName("vod")] [ConfigurationKeyName("vod")]
public Vod Vod { get; set; } public Vod Vod { get; set; }
[ConfigurationKeyName("clip")]
public Clip Clip { get; set; }
[ConfigurationKeyName("channel")]
public Channel Channel { get; set; }
} }
} }

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VDownload.Sources.Twitch.Models
{
public class TwitchChannel : TwitchPlaylist
{
#region PROPERTIES
public required string Id { get; set; }
#endregion
}
}

View File

@@ -9,5 +9,13 @@ namespace VDownload.Sources.Twitch.Models
{ {
public abstract class TwitchPlaylist : Playlist public abstract class TwitchPlaylist : Playlist
{ {
#region CONSTRUCTORS
protected TwitchPlaylist()
{
Source = Source.Twitch;
}
#endregion
} }
} }

View File

@@ -9,6 +9,7 @@ using VDownload.Services.Data.Configuration;
using VDownload.Sources.Common; using VDownload.Sources.Common;
using VDownload.Sources.Twitch.Api; using VDownload.Sources.Twitch.Api;
using VDownload.Sources.Twitch.Api.GQL.GetVideoToken.Response; using VDownload.Sources.Twitch.Api.GQL.GetVideoToken.Response;
using VDownload.Sources.Twitch.Api.Helix.GetUsers.Response;
using VDownload.Sources.Twitch.Api.Helix.GetVideos.Response; using VDownload.Sources.Twitch.Api.Helix.GetVideos.Response;
using VDownload.Sources.Twitch.Authentication; using VDownload.Sources.Twitch.Authentication;
using VDownload.Sources.Twitch.Configuration.Models; using VDownload.Sources.Twitch.Configuration.Models;
@@ -71,7 +72,16 @@ namespace VDownload.Sources.Twitch
async Task<Playlist> ISourceSearchService.SearchPlaylist(string url, int maxVideoCount) => await SearchPlaylist(url, maxVideoCount); async Task<Playlist> ISourceSearchService.SearchPlaylist(string url, int maxVideoCount) => await SearchPlaylist(url, maxVideoCount);
public async Task<TwitchPlaylist> SearchPlaylist(string url, int maxVideoCount) public async Task<TwitchPlaylist> SearchPlaylist(string url, int maxVideoCount)
{ {
throw new NotImplementedException(); foreach (Regex regex in _configurationService.Twitch.Search.Channel.Regexes.Select(x => new Regex(x)))
{
Match match = regex.Match(url);
if (match.Success)
{
string id = match.Groups[1].Value;
return await GetChannel(id, maxVideoCount);
}
}
throw new MediaSearchException("Invalid url");
} }
#endregion #endregion
@@ -82,23 +92,68 @@ namespace VDownload.Sources.Twitch
protected async Task<TwitchVod> GetVod(string id) protected async Task<TwitchVod> GetVod(string id)
{ {
Task<IEnumerable<TwitchVodStream>> streamsTask = GetVodStreams(id);
byte[] token = await GetToken(); byte[] token = await GetToken();
GetVideosResponse info = await _apiService.HelixGetVideos(id, token);
Data vodResponse = info.Data[0]; GetVideosResponse info = await _apiService.HelixGetVideo(id, token);
Api.Helix.GetVideos.Response.Data vodResponse = info.Data[0];
TwitchVod vod = await ParseVod(vodResponse);
return vod;
}
protected async Task<TwitchChannel> GetChannel(string id, int count)
{
byte[] token = await GetToken();
GetUsersResponse info = await _apiService.HelixGetUser(id, token);
Api.Helix.GetUsers.Response.Data userResponse = info.Data[0];
TwitchChannel channel = new TwitchChannel
{
Id = userResponse.Id,
Name = userResponse.DisplayName,
Description = userResponse.Description,
Url = new Uri(string.Format(_configurationService.Twitch.Search.Channel.Url, id)),
};
List<Task<TwitchVod>> tasks = new List<Task<TwitchVod>>();
string? cursor = null;
List<Api.Helix.GetVideos.Response.Data> videosList;
int videos = 0;
do
{
videos = count == 0 || count > 100 ? 100 : count;
GetVideosResponse videosResponse = await _apiService.HelixGetUserVideos(channel.Id, token, videos, cursor);
videosList = videosResponse.Data;
count -= videosList.Count;
cursor = videosResponse.Pagination.Cursor;
tasks.AddRange(videosList.Select(ParseVod));
}
while (videosList.Count == videos);
await Task.WhenAll(tasks);
channel.AddRange(tasks.Select(x => x.Result));
return channel;
}
public async Task<TwitchVod> ParseVod(Api.Helix.GetVideos.Response.Data data)
{
Task<IEnumerable<TwitchVodStream>> streamsTask = GetVodStreams(data.Id);
Thumbnail thumbnail = _configurationService.Twitch.Search.Vod.Thumbnail; Thumbnail thumbnail = _configurationService.Twitch.Search.Vod.Thumbnail;
TwitchVod vod = new TwitchVod TwitchVod vod = new TwitchVod
{ {
Title = vodResponse.Title, Title = data.Title,
Description = vodResponse.Description, Description = data.Description,
Author = vodResponse.UserName, Author = data.UserName,
PublishDate = vodResponse.PublishedAt, PublishDate = data.PublishedAt,
Duration = ParseVodDuration(vodResponse.Duration), Duration = ParseVodDuration(data.Duration),
Views = vodResponse.ViewCount, Views = data.ViewCount,
ThumbnailUrl = new Uri(vodResponse.ThumbnailUrl.Replace("%{width}", thumbnail.Width.ToString()).Replace("%{height}", thumbnail.Height.ToString())), ThumbnailUrl = new Uri(data.ThumbnailUrl.Replace("%{width}", thumbnail.Width.ToString()).Replace("%{height}", thumbnail.Height.ToString())),
Url = new Uri(vodResponse.Url), Url = new Uri(data.Url),
}; };
await streamsTask; await streamsTask;

View File

@@ -1,34 +0,0 @@
namespace VDownload.Toolkit.Extensions
{
public static class StringExtensions
{
#region STATIC
public static string CreateRandom(int length) => CreateRandom(length, "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890`~!@#$%^&*()-_=+[{]};:'\"\\|,<.>/?");
public static string CreateRandom(int length, IEnumerable<char> characters) => new string(Enumerable.Repeat(characters, length).Select(s => s.ElementAt(Random.Shared.Next(s.Count()))).ToArray());
#endregion
#region INSTANCE
public static string Shuffle(this string instance)
{
char[] array = instance.ToCharArray();
Random rng = Random.Shared;
int n = array.Length;
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
char value = array[k];
array[k] = array[n];
array[n] = value;
}
return new string(array);
}
#endregion
}
}

View File

@@ -1,9 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -1,91 +0,0 @@
using Microsoft.UI.Xaml;
using Microsoft.Xaml.Interactivity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace VDownload.Toolkit.UI.Behaviors
{
public class EventToCommandBehavior : Behavior<FrameworkElement>
{
#region FIELDS
private Delegate _handler;
private EventInfo _oldEvent;
#endregion
#region PROPERTIES
public string Event { get { return (string)GetValue(EventProperty); } set { SetValue(EventProperty, value); } }
public static readonly DependencyProperty EventProperty = DependencyProperty.Register("Event", typeof(string), typeof(EventToCommandBehavior), new PropertyMetadata(null, OnEventChanged));
public ICommand Command { get { return (ICommand)GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } }
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(EventToCommandBehavior), new PropertyMetadata(null));
public bool PassArguments { get { return (bool)GetValue(PassArgumentsProperty); } set { SetValue(PassArgumentsProperty, value); } }
public static readonly DependencyProperty PassArgumentsProperty = DependencyProperty.Register("PassArguments", typeof(bool), typeof(EventToCommandBehavior), new PropertyMetadata(false));
#endregion
#region PRIVATE METHODS
private static void OnEventChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
EventToCommandBehavior beh = (EventToCommandBehavior)d;
if (beh.AssociatedObject != null)
{
beh.AttachHandler((string)e.NewValue);
}
}
protected override void OnAttached()
{
AttachHandler(this.Event);
}
private void AttachHandler(string eventName)
{
if (_oldEvent != null)
{
_oldEvent.RemoveEventHandler(this.AssociatedObject, _handler);
}
if (!string.IsNullOrEmpty(eventName))
{
EventInfo ei = this.AssociatedObject.GetType().GetEvent(eventName);
if (ei != null)
{
MethodInfo mi = this.GetType().GetMethod("ExecuteCommand", BindingFlags.Instance | BindingFlags.NonPublic);
_handler = Delegate.CreateDelegate(ei.EventHandlerType, this, mi);
ei.AddEventHandler(this.AssociatedObject, _handler);
_oldEvent = ei;
}
else
{
throw new ArgumentException(string.Format("The event '{0}' was not found on type '{1}'", eventName, this.AssociatedObject.GetType().Name));
}
}
}
private void ExecuteCommand(object sender, object e)
{
object parameter = this.PassArguments ? e : null;
if (this.Command != null && this.Command.CanExecute(parameter))
{
this.Command.Execute(parameter);
}
}
#endregion
}
}

View File

@@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<RootNamespace>VDownload.Toolkit.UI.Behaviors</RootNamespace>
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
<UseWinUI>true</UseWinUI>
<UseRidGraph>true</UseRidGraph>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.240211001" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
</ItemGroup>
</Project>

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<UserControl
x:Class="VDownload.Toolkit.UI.Controls.TimeSpanControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Name="Control"
Loaded="Control_Loaded">
<StackPanel Orientation="Horizontal" Spacing="4">
<NumberBox x:Name="Hours" SpinButtonPlacementMode="Compact" Minimum="0" Value="0" ValueChanged="ValueChanged"/>
<TextBlock VerticalAlignment="Center" Padding="0,0,0,5" Text=":"/>
<NumberBox x:Name="Minutes" SpinButtonPlacementMode="Compact" Minimum="0" Value="0" Maximum="59" ValueChanged="ValueChanged"/>
<TextBlock VerticalAlignment="Center" Padding="0,0,0,5" Text=":"/>
<NumberBox x:Name="Seconds" SpinButtonPlacementMode="Compact" Minimum="0" Value="0" Maximum="59" ValueChanged="ValueChanged"/>
</StackPanel>
</UserControl>

View File

@@ -1,119 +0,0 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
namespace VDownload.Toolkit.UI.Controls
{
public sealed partial class TimeSpanControl : UserControl
{
#region PROPERTIES
public TimeSpan Value
{
get => (TimeSpan)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(TimeSpan), typeof(TimeSpanControl), new PropertyMetadata(TimeSpan.Zero, new PropertyChangedCallback(ValuePropertyChanged)));
public TimeSpan Maximum
{
get => (TimeSpan)GetValue(MaximumProperty);
set => SetValue(MaximumProperty, value);
}
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(TimeSpan), typeof(TimeSpanControl), new PropertyMetadata(TimeSpan.MaxValue, new PropertyChangedCallback(RangePropertyChanged)));
public TimeSpan Minimum
{
get => (TimeSpan)GetValue(MinimumProperty);
set => SetValue(MinimumProperty, value);
}
public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(TimeSpan), typeof(TimeSpanControl), new PropertyMetadata(TimeSpan.Zero, new PropertyChangedCallback(RangePropertyChanged)));
#endregion
#region CONSTRUCTORS
public TimeSpanControl()
{
this.InitializeComponent();
}
#endregion
#region PRIVATE METHODS
private void UpdateOnChanges()
{
if (this.IsLoaded)
{
TimeSpan hoursTimeSpan = TimeSpan.FromHours(Hours.Value);
TimeSpan minutesTimeSpan = TimeSpan.FromMinutes(Minutes.Value);
TimeSpan secondsTimeSpan = TimeSpan.FromSeconds(Seconds.Value);
TimeSpan value = secondsTimeSpan + minutesTimeSpan + hoursTimeSpan;
if (value >= Maximum)
{
Hours.Value = Math.Floor(Maximum.TotalHours);
Minutes.Value = Maximum.Minutes;
Seconds.Value = Maximum.Seconds;
}
else if (value <= Minimum)
{
Hours.Value = Math.Floor(Minimum.TotalHours);
Minutes.Value = Minimum.Minutes;
Seconds.Value = Minimum.Seconds;
}
Value = value;
}
}
private void UpdateOnValueChange()
{
if (this.IsLoaded)
{
TimeSpan value = Value;
if (value > Maximum)
{
value = Maximum;
}
else if (value < Minimum)
{
value = Minimum;
}
Hours.Value = Math.Floor(value.TotalHours);
Minutes.Value = value.Minutes;
Seconds.Value = value.Seconds;
}
}
#endregion
#region EVENT HANDLERS
private void ValueChanged(NumberBox sender, NumberBoxValueChangedEventArgs args) => UpdateOnChanges();
private static void ValuePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) => ((TimeSpanControl)obj).UpdateOnValueChange();
private static void RangePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) => ((TimeSpanControl)obj).UpdateOnChanges();
private void Control_Loaded(object sender, RoutedEventArgs e) => UpdateOnValueChange();
#endregion
}
}

View File

@@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<RootNamespace>VDownload.Toolkit.UI.Controls</RootNamespace>
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
<UseWinUI>true</UseWinUI>
<UseRidGraph>true</UseRidGraph>
</PropertyGroup>
<ItemGroup>
<None Remove="TimeSpanControl.xaml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.240211001" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
</ItemGroup>
<ItemGroup>
<Page Update="TimeSpanControl.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
</Project>

View File

@@ -1,22 +0,0 @@
using Microsoft.UI.Xaml.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VDownload.Toolkit.UI.Converters
{
public class ObjectToIntConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return (int)value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,20 +0,0 @@
using Microsoft.UI.Xaml.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VDownload.Toolkit.UI.Converters
{
public class ObjectToStringConverter : IValueConverter
{
#region METHODS
public object Convert(object value, Type targetType, object parameter, string language) => value.ToString();
public object ConvertBack(object value, Type targetType, object parameter, string language) => throw new NotImplementedException();
#endregion
}
}

View File

@@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<RootNamespace>VDownload.Toolkit.UI.Converters</RootNamespace>
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
<UseWinUI>true</UseWinUI>
<UseRidGraph>true</UseRidGraph>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.240211001" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
</ItemGroup>
</Project>

View File

@@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VDownload.Toolkit.UI.Models
{
public class NavigationViewItem
{
#region PROPERTIES
public string Name { get; set; }
public string IconSource { get; set; }
public Type ViewModel { get; set; }
#endregion
}
}

View File

@@ -1,9 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -5,18 +5,6 @@ VisualStudioVersion = 17.8.34330.188
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload", "VDownload\VDownload.csproj", "{62A8EAD3-6D6A-40FC-9E1E-C57C02E27244}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload", "VDownload\VDownload.csproj", "{62A8EAD3-6D6A-40FC-9E1E-C57C02E27244}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VDownload.Toolkit", "VDownload.Toolkit", "{5881405B-CA88-4A10-A8AC-1822249AC0FA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VDownload.Toolkit.UI", "VDownload.Toolkit.UI", "{2DABFD88-246F-47C2-B752-24DCF7477CEC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Toolkit.UI.Controls", "VDownload.Toolkit\VDownload.Toolkit.UI\VDownload.Toolkit.UI.Controls\VDownload.Toolkit.UI.Controls.csproj", "{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Toolkit.UI.Converters", "VDownload.Toolkit\VDownload.Toolkit.UI\VDownload.Toolkit.UI.Converters\VDownload.Toolkit.UI.Converters.csproj", "{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Toolkit.UI.Behaviors", "VDownload.Toolkit\VDownload.Toolkit.UI\VDownload.Toolkit.UI.Behaviors\VDownload.Toolkit.UI.Behaviors.csproj", "{5DB5CE22-96F4-4789-8A48-4F3C164A5972}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Toolkit.Extensions", "VDownload.Toolkit\VDownload.Toolkit.Extensions\VDownload.Toolkit.Extensions.csproj", "{8091445A-2CAB-43A4-9459-745974D69834}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VDownload.Sources", "VDownload.Sources", "{9A8EB967-1EAB-439E-8FDB-B9ACAC6499EC}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VDownload.Sources", "VDownload.Sources", "{9A8EB967-1EAB-439E-8FDB-B9ACAC6499EC}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VDownload.Sources.Twitch", "VDownload.Sources.Twitch", "{8D94F264-4EE9-4C24-AB77-2CCA36858309}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VDownload.Sources.Twitch", "VDownload.Sources.Twitch", "{8D94F264-4EE9-4C24-AB77-2CCA36858309}"
@@ -69,8 +57,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Services.UI.Strin
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Services.UI.DictionaryResources", "VDownload.Services\VDownload.Services.UI\VDownload.Services.UI.DictionaryResources\VDownload.Services.UI.DictionaryResources.csproj", "{8DC55331-B9F3-4811-8474-348662963260}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Services.UI.DictionaryResources", "VDownload.Services\VDownload.Services.UI\VDownload.Services.UI.DictionaryResources\VDownload.Services.UI.DictionaryResources.csproj", "{8DC55331-B9F3-4811-8474-348662963260}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Toolkit.UI.Models", "VDownload.Toolkit\VDownload.Toolkit.UI\VDownload.Toolkit.UI.Models\VDownload.Toolkit.UI.Models.csproj", "{C3C44E06-E03A-4971-99DA-06F6AD606B3B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Sources.Twitch.Settings", "VDownload.Sources\VDownload.Sources.Twitch\VDownload.Sources.Twitch.Settings\VDownload.Sources.Twitch.Settings.csproj", "{A726FD43-B111-423B-BAF6-D65B4C0E37B5}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Sources.Twitch.Settings", "VDownload.Sources\VDownload.Sources.Twitch\VDownload.Sources.Twitch.Settings\VDownload.Sources.Twitch.Settings.csproj", "{A726FD43-B111-423B-BAF6-D65B4C0E37B5}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Core.Strings", "VDownload.Core\VDownload.Core.Strings\VDownload.Core.Strings.csproj", "{E1D4352C-51AC-4572-8515-0B4E89A2442F}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Core.Strings", "VDownload.Core\VDownload.Core.Strings\VDownload.Core.Strings.csproj", "{E1D4352C-51AC-4572-8515-0B4E89A2442F}"
@@ -79,9 +65,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Core.ViewModels",
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Core.Views", "VDownload.Core\VDownload.Core.Views\VDownload.Core.Views.csproj", "{E470FCE2-DB0D-4771-8C9D-43D8AB85FB80}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Core.Views", "VDownload.Core\VDownload.Core.Views\VDownload.Core.Views.csproj", "{E470FCE2-DB0D-4771-8C9D-43D8AB85FB80}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VDownload.Core.Tasks", "VDownload.Core\VDownload.Core.Tasks\VDownload.Core.Tasks.csproj", "{3BE998A3-1126-4496-BF60-80D0CEA4D24F}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Core.Tasks", "VDownload.Core\VDownload.Core.Tasks\VDownload.Core.Tasks.csproj", "{3BE998A3-1126-4496-BF60-80D0CEA4D24F}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VDownload.Services.Utility.FFmpeg", "VDownload.Services\VDownload.Services.Utility\VDownload.Services.Utility.FFmpeg\VDownload.Services.Utility.FFmpeg.csproj", "{A3166F8A-ECAD-4D4B-9BE3-96FEC799B27B}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDownload.Services.Utility.FFmpeg", "VDownload.Services\VDownload.Services.Utility\VDownload.Services.Utility.FFmpeg\VDownload.Services.Utility.FFmpeg.csproj", "{A3166F8A-ECAD-4D4B-9BE3-96FEC799B27B}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -117,70 +103,6 @@ Global
{62A8EAD3-6D6A-40FC-9E1E-C57C02E27244}.Release|x86.ActiveCfg = Release|x86 {62A8EAD3-6D6A-40FC-9E1E-C57C02E27244}.Release|x86.ActiveCfg = Release|x86
{62A8EAD3-6D6A-40FC-9E1E-C57C02E27244}.Release|x86.Build.0 = Release|x86 {62A8EAD3-6D6A-40FC-9E1E-C57C02E27244}.Release|x86.Build.0 = Release|x86
{62A8EAD3-6D6A-40FC-9E1E-C57C02E27244}.Release|x86.Deploy.0 = Release|x86 {62A8EAD3-6D6A-40FC-9E1E-C57C02E27244}.Release|x86.Deploy.0 = Release|x86
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Debug|ARM64.Build.0 = Debug|Any CPU
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Debug|x64.ActiveCfg = Debug|Any CPU
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Debug|x64.Build.0 = Debug|Any CPU
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Debug|x86.ActiveCfg = Debug|Any CPU
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Debug|x86.Build.0 = Debug|Any CPU
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Release|Any CPU.Build.0 = Release|Any CPU
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Release|ARM64.ActiveCfg = Release|Any CPU
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Release|ARM64.Build.0 = Release|Any CPU
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Release|x64.ActiveCfg = Release|Any CPU
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Release|x64.Build.0 = Release|Any CPU
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Release|x86.ActiveCfg = Release|Any CPU
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74}.Release|x86.Build.0 = Release|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Debug|ARM64.Build.0 = Debug|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Debug|x64.ActiveCfg = Debug|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Debug|x64.Build.0 = Debug|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Debug|x86.ActiveCfg = Debug|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Debug|x86.Build.0 = Debug|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Release|Any CPU.Build.0 = Release|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Release|ARM64.ActiveCfg = Release|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Release|ARM64.Build.0 = Release|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Release|x64.ActiveCfg = Release|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Release|x64.Build.0 = Release|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Release|x86.ActiveCfg = Release|Any CPU
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D}.Release|x86.Build.0 = Release|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Debug|ARM64.Build.0 = Debug|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Debug|x64.ActiveCfg = Debug|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Debug|x64.Build.0 = Debug|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Debug|x86.ActiveCfg = Debug|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Debug|x86.Build.0 = Debug|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Release|Any CPU.Build.0 = Release|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Release|ARM64.ActiveCfg = Release|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Release|ARM64.Build.0 = Release|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Release|x64.ActiveCfg = Release|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Release|x64.Build.0 = Release|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Release|x86.ActiveCfg = Release|Any CPU
{5DB5CE22-96F4-4789-8A48-4F3C164A5972}.Release|x86.Build.0 = Release|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Debug|ARM64.Build.0 = Debug|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Debug|x64.ActiveCfg = Debug|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Debug|x64.Build.0 = Debug|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Debug|x86.ActiveCfg = Debug|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Debug|x86.Build.0 = Debug|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Release|Any CPU.Build.0 = Release|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Release|ARM64.ActiveCfg = Release|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Release|ARM64.Build.0 = Release|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Release|x64.ActiveCfg = Release|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Release|x64.Build.0 = Release|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Release|x86.ActiveCfg = Release|Any CPU
{8091445A-2CAB-43A4-9459-745974D69834}.Release|x86.Build.0 = Release|Any CPU
{FB21E094-B723-4E7F-B7CB-434BF19B66E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FB21E094-B723-4E7F-B7CB-434BF19B66E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FB21E094-B723-4E7F-B7CB-434BF19B66E1}.Debug|Any CPU.Build.0 = Debug|Any CPU {FB21E094-B723-4E7F-B7CB-434BF19B66E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FB21E094-B723-4E7F-B7CB-434BF19B66E1}.Debug|ARM64.ActiveCfg = Debug|Any CPU {FB21E094-B723-4E7F-B7CB-434BF19B66E1}.Debug|ARM64.ActiveCfg = Debug|Any CPU
@@ -485,22 +407,6 @@ Global
{8DC55331-B9F3-4811-8474-348662963260}.Release|x64.Build.0 = Release|Any CPU {8DC55331-B9F3-4811-8474-348662963260}.Release|x64.Build.0 = Release|Any CPU
{8DC55331-B9F3-4811-8474-348662963260}.Release|x86.ActiveCfg = Release|Any CPU {8DC55331-B9F3-4811-8474-348662963260}.Release|x86.ActiveCfg = Release|Any CPU
{8DC55331-B9F3-4811-8474-348662963260}.Release|x86.Build.0 = Release|Any CPU {8DC55331-B9F3-4811-8474-348662963260}.Release|x86.Build.0 = Release|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Debug|ARM64.Build.0 = Debug|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Debug|x64.ActiveCfg = Debug|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Debug|x64.Build.0 = Debug|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Debug|x86.ActiveCfg = Debug|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Debug|x86.Build.0 = Debug|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Release|Any CPU.Build.0 = Release|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Release|ARM64.ActiveCfg = Release|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Release|ARM64.Build.0 = Release|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Release|x64.ActiveCfg = Release|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Release|x64.Build.0 = Release|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Release|x86.ActiveCfg = Release|Any CPU
{C3C44E06-E03A-4971-99DA-06F6AD606B3B}.Release|x86.Build.0 = Release|Any CPU
{A726FD43-B111-423B-BAF6-D65B4C0E37B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A726FD43-B111-423B-BAF6-D65B4C0E37B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A726FD43-B111-423B-BAF6-D65B4C0E37B5}.Debug|Any CPU.Build.0 = Debug|Any CPU {A726FD43-B111-423B-BAF6-D65B4C0E37B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A726FD43-B111-423B-BAF6-D65B4C0E37B5}.Debug|ARM64.ActiveCfg = Debug|Any CPU {A726FD43-B111-423B-BAF6-D65B4C0E37B5}.Debug|ARM64.ActiveCfg = Debug|Any CPU
@@ -602,11 +508,6 @@ Global
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{2DABFD88-246F-47C2-B752-24DCF7477CEC} = {5881405B-CA88-4A10-A8AC-1822249AC0FA}
{4D762F1C-0905-4B82-9F2C-C0FCD96E2F74} = {2DABFD88-246F-47C2-B752-24DCF7477CEC}
{D6C92F41-B72D-4FE3-AF1C-C1D093CF312D} = {2DABFD88-246F-47C2-B752-24DCF7477CEC}
{5DB5CE22-96F4-4789-8A48-4F3C164A5972} = {2DABFD88-246F-47C2-B752-24DCF7477CEC}
{8091445A-2CAB-43A4-9459-745974D69834} = {5881405B-CA88-4A10-A8AC-1822249AC0FA}
{8D94F264-4EE9-4C24-AB77-2CCA36858309} = {9A8EB967-1EAB-439E-8FDB-B9ACAC6499EC} {8D94F264-4EE9-4C24-AB77-2CCA36858309} = {9A8EB967-1EAB-439E-8FDB-B9ACAC6499EC}
{4CC2DC7D-27D2-4F52-89DF-7D45B41BB40F} = {8D351DB0-74E6-4C1E-A123-34D6BBBD5585} {4CC2DC7D-27D2-4F52-89DF-7D45B41BB40F} = {8D351DB0-74E6-4C1E-A123-34D6BBBD5585}
{05A45688-7EEF-4656-818A-2477625C3707} = {8D351DB0-74E6-4C1E-A123-34D6BBBD5585} {05A45688-7EEF-4656-818A-2477625C3707} = {8D351DB0-74E6-4C1E-A123-34D6BBBD5585}
@@ -629,7 +530,6 @@ Global
{64A217AE-4E95-468E-85C3-67C27D689FF4} = {9A8EB967-1EAB-439E-8FDB-B9ACAC6499EC} {64A217AE-4E95-468E-85C3-67C27D689FF4} = {9A8EB967-1EAB-439E-8FDB-B9ACAC6499EC}
{6F6CA153-1AC6-454A-ACDC-2C706E2A437E} = {4CC2DC7D-27D2-4F52-89DF-7D45B41BB40F} {6F6CA153-1AC6-454A-ACDC-2C706E2A437E} = {4CC2DC7D-27D2-4F52-89DF-7D45B41BB40F}
{8DC55331-B9F3-4811-8474-348662963260} = {4CC2DC7D-27D2-4F52-89DF-7D45B41BB40F} {8DC55331-B9F3-4811-8474-348662963260} = {4CC2DC7D-27D2-4F52-89DF-7D45B41BB40F}
{C3C44E06-E03A-4971-99DA-06F6AD606B3B} = {2DABFD88-246F-47C2-B752-24DCF7477CEC}
{A726FD43-B111-423B-BAF6-D65B4C0E37B5} = {8D94F264-4EE9-4C24-AB77-2CCA36858309} {A726FD43-B111-423B-BAF6-D65B4C0E37B5} = {8D94F264-4EE9-4C24-AB77-2CCA36858309}
{E1D4352C-51AC-4572-8515-0B4E89A2442F} = {8539067C-9968-4AEB-928C-FEDC43989A79} {E1D4352C-51AC-4572-8515-0B4E89A2442F} = {8539067C-9968-4AEB-928C-FEDC43989A79}
{54DCFBDC-7A2E-439A-92F5-E5A19A2D0DFC} = {8539067C-9968-4AEB-928C-FEDC43989A79} {54DCFBDC-7A2E-439A-92F5-E5A19A2D0DFC} = {8539067C-9968-4AEB-928C-FEDC43989A79}

View File

@@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using System; using System;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks;
using VDownload.Core.Tasks; using VDownload.Core.Tasks;
using VDownload.Core.ViewModels; using VDownload.Core.ViewModels;
using VDownload.Core.ViewModels.Authentication; using VDownload.Core.ViewModels.Authentication;
@@ -145,6 +146,7 @@ namespace VDownload
services.AddSingleton<SettingsViewModel>(); services.AddSingleton<SettingsViewModel>();
services.AddSingleton<HomeDownloadsViewModel>(); services.AddSingleton<HomeDownloadsViewModel>();
services.AddSingleton<HomeVideoViewModel>(); services.AddSingleton<HomeVideoViewModel>();
services.AddSingleton<HomePlaylistViewModel>();
services.AddSingleton<HomeViewModel>(); services.AddSingleton<HomeViewModel>();
services.AddSingleton<BaseViewModel>(); services.AddSingleton<BaseViewModel>();
@@ -153,10 +155,29 @@ namespace VDownload
services.AddTransient<SettingsView>(); services.AddTransient<SettingsView>();
services.AddTransient<HomeDownloadsView>(); services.AddTransient<HomeDownloadsView>();
services.AddTransient<HomeVideoView>(); services.AddTransient<HomeVideoView>();
services.AddTransient<HomePlaylistView>();
services.AddTransient<HomeView>(); services.AddTransient<HomeView>();
services.AddTransient<BaseWindow>(); services.AddTransient<BaseWindow>();
} }
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
await InitData();
_window = _serviceProvider.GetService<BaseWindow>();
_window.RootLoaded += Window_RootLoaded;
_window.Activate();
AssignStaticProperties();
}
protected async Task InitData()
{
ISettingsService settingsService = _serviceProvider.GetService<ISettingsService>();
IAuthenticationDataService authenticationDataService = _serviceProvider.GetService<IAuthenticationDataService>();
await Task.WhenAll(settingsService.Load(), authenticationDataService.Load());
}
protected void AssignStaticProperties() protected void AssignStaticProperties()
{ {
IStoragePickerService storagePickerService = _serviceProvider.GetService<IStoragePickerService>(); IStoragePickerService storagePickerService = _serviceProvider.GetService<IStoragePickerService>();
@@ -165,15 +186,6 @@ namespace VDownload
ViewModelToViewConverter.ServiceProvider = _serviceProvider; ViewModelToViewConverter.ServiceProvider = _serviceProvider;
} }
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
_window = _serviceProvider.GetService<BaseWindow>();
_window.RootLoaded += Window_RootLoaded;
_window.Activate();
AssignStaticProperties();
}
protected void Window_RootLoaded(object sender, EventArgs e) protected void Window_RootLoaded(object sender, EventArgs e)
{ {
IDialogsService dialogsService = _serviceProvider.GetService<IDialogsService>(); IDialogsService dialogsService = _serviceProvider.GetService<IDialogsService>();

View File

@@ -3,7 +3,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:v="using:VDownload.Core.Views" xmlns:v="using:VDownload.Core.Views"
xmlns:lt="using:VDownload.Toolkit.UI.Converters" xmlns:lt="using:SimpleToolkit.UI.WinUI.Converters"
xmlns:ct="using:CommunityToolkit.WinUI.Converters"> xmlns:ct="using:CommunityToolkit.WinUI.Converters">
<v:ViewModelToViewConverter x:Key="ViewModelToViewConverter"/> <v:ViewModelToViewConverter x:Key="ViewModelToViewConverter"/>

View File

@@ -132,6 +132,7 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.240211001" /> <PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.240211001" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" /> <PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
<PackageReference Include="SimpleToolkit.UI.WinUI.Converters" Version="1.4.0" />
<Manifest Include="$(ApplicationManifest)" /> <Manifest Include="$(ApplicationManifest)" />
</ItemGroup> </ItemGroup>
@@ -160,7 +161,6 @@
<ProjectReference Include="..\VDownload.Sources\VDownload.Sources.Twitch\VDownload.Sources.Twitch.Authentication\VDownload.Sources.Twitch.Authentication.csproj" /> <ProjectReference Include="..\VDownload.Sources\VDownload.Sources.Twitch\VDownload.Sources.Twitch.Authentication\VDownload.Sources.Twitch.Authentication.csproj" />
<ProjectReference Include="..\VDownload.Sources\VDownload.Sources.Twitch\VDownload.Sources.Twitch\VDownload.Sources.Twitch.csproj" /> <ProjectReference Include="..\VDownload.Sources\VDownload.Sources.Twitch\VDownload.Sources.Twitch\VDownload.Sources.Twitch.csproj" />
<ProjectReference Include="..\VDownload.Sources\VDownload.Sources\VDownload.Sources.csproj" /> <ProjectReference Include="..\VDownload.Sources\VDownload.Sources\VDownload.Sources.csproj" />
<ProjectReference Include="..\VDownload.Toolkit\VDownload.Toolkit.UI\VDownload.Toolkit.UI.Converters\VDownload.Toolkit.UI.Converters.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="Assets\BaseView\AuthenticationDark.png"> <None Update="Assets\BaseView\AuthenticationDark.png">

View File

@@ -116,7 +116,8 @@
"token_schema": "Bearer", "token_schema": "Bearer",
"client_id": "yukkqkwp61wsv3u1pya17crpyaa98y", "client_id": "yukkqkwp61wsv3u1pya17crpyaa98y",
"endpoints": { "endpoints": {
"get_videos": "https://api.twitch.tv/helix/videos" "get_videos": "https://api.twitch.tv/helix/videos",
"get_users": "https://api.twitch.tv/helix/users"
} }
}, },
"gql": { "gql": {
@@ -148,6 +149,18 @@
"height": 1080 "height": 1080
}, },
"stream_playlist_regex": "#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID=\"\\w+\",NAME=\"(?<id>.+)\",AUTOSELECT=\\w+,DEFAULT=\\w+\\n#EXT-X-STREAM-INF:BANDWIDTH=\\d+,CODECS=\"(?<video_codec>.+),(?<audio_codec>.+)\",RESOLUTION=(?<width>\\d+)x(?<height>\\d+),VIDEO=\".+\"(?:,FRAME-RATE=(?<framerate>\\d+.\\d+))?\n(?<url>.+)" "stream_playlist_regex": "#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID=\"\\w+\",NAME=\"(?<id>.+)\",AUTOSELECT=\\w+,DEFAULT=\\w+\\n#EXT-X-STREAM-INF:BANDWIDTH=\\d+,CODECS=\"(?<video_codec>.+),(?<audio_codec>.+)\",RESOLUTION=(?<width>\\d+)x(?<height>\\d+),VIDEO=\".+\"(?:,FRAME-RATE=(?<framerate>\\d+.\\d+))?\n(?<url>.+)"
},
"clip": {
"regexes": [
"clip\\/(\\w+-\\w+)",
"clips\\.twitch\\.tv\\/(\\w+-\\w+)"
]
},
"channel": {
"regexes": [
"twitch\\.tv\\/(\\w+)(?:\\/)?(?:\\/videos)?$"
],
"url": "https://www.twitch.tv/{0}"
} }
}, },
"download": { "download": {