Compare commits
1 Commits
master
...
ffmpeg-msb
Author | SHA1 | Date | |
---|---|---|---|
|
6dbfd290fa |
31
.github/workflows/main.yml
vendored
31
.github/workflows/main.yml
vendored
@ -60,8 +60,6 @@ jobs:
|
||||
- win-x86
|
||||
- win-x64
|
||||
- linux-arm64
|
||||
# Linux x86 is not supported by .NET
|
||||
# - linux-x86
|
||||
- linux-x64
|
||||
- osx-arm64
|
||||
- osx-x64
|
||||
@ -73,6 +71,10 @@ jobs:
|
||||
artifact-name-base: YoutubeDownloader
|
||||
- bundle-ffmpeg: false
|
||||
artifact-name-base: YoutubeDownloader.Bare
|
||||
exclude:
|
||||
# FFmpeg builds for these platforms are not easily available
|
||||
- bundle-ffmpeg: true
|
||||
rid: linux-arm64
|
||||
|
||||
runs-on: ${{ startsWith(matrix.rid, 'win-') && 'windows-latest' || startsWith(matrix.rid, 'osx-') && 'macos-latest' || 'ubuntu-latest' }}
|
||||
timeout-minutes: 10
|
||||
@ -96,13 +98,12 @@ jobs:
|
||||
-p:Version=${{ github.ref_type == 'tag' && github.ref_name || format('999.9.9-ci-{0}', github.sha) }}
|
||||
-p:CSharpier_Bypass=true
|
||||
-p:DownloadFFmpeg=${{ matrix.bundle-ffmpeg }}
|
||||
-p:PublishMacOSBundle=${{ startsWith(matrix.rid, 'osx-') }}
|
||||
--output YoutubeDownloader/bin/publish
|
||||
--configuration Release
|
||||
--runtime ${{ matrix.rid }}
|
||||
--self-contained
|
||||
|
||||
- name: Upload app binaries
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: ${{ matrix.artifact-name-base }}.${{ matrix.rid }}
|
||||
@ -143,8 +144,6 @@ jobs:
|
||||
- win-x86
|
||||
- win-x64
|
||||
- linux-arm64
|
||||
# Linux x86 is not supported by .NET
|
||||
# - linux-x86
|
||||
- linux-x64
|
||||
- osx-arm64
|
||||
- osx-x64
|
||||
@ -156,6 +155,10 @@ jobs:
|
||||
artifact-name-base: YoutubeDownloader
|
||||
- bundle-ffmpeg: false
|
||||
artifact-name-base: YoutubeDownloader.Bare
|
||||
exclude:
|
||||
# FFmpeg builds for these platforms are not easily available
|
||||
- bundle-ffmpeg: true
|
||||
rid: linux-arm64
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
@ -165,21 +168,19 @@ jobs:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Download app binaries
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: ${{ matrix.artifact-name-base }}.${{ matrix.rid }}
|
||||
path: YoutubeDownloader/
|
||||
|
||||
- name: Set permissions
|
||||
- name: Set permissions (app)
|
||||
if: ${{ !startsWith(matrix.rid, 'win-') }}
|
||||
run: |
|
||||
[ -f YoutubeDownloader/YoutubeDownloader ] && chmod +x YoutubeDownloader/YoutubeDownloader
|
||||
[ -f YoutubeDownloader/ffmpeg ] && chmod +x YoutubeDownloader/ffmpeg
|
||||
|
||||
# macOS bundle
|
||||
[ -f YoutubeDownloader/YoutubeDownloader.app/Contents/MacOS/YoutubeDownloader] && chmod +x YoutubeDownloader/YoutubeDownloader.app/Contents/MacOS/YoutubeDownloader
|
||||
[ -f YoutubeDownloader/YoutubeDownloader.app/Contents/MacOS/ffmpeg ] && chmod +x YoutubeDownloader/YoutubeDownloader.app/Contents/MacOS/ffmpeg
|
||||
run: chmod +x YoutubeDownloader/YoutubeDownloader
|
||||
|
||||
- name: Set permissions (FFmpeg)
|
||||
if: ${{ !startsWith(matrix.rid, 'win-') && matrix.bundle-ffmpeg }}
|
||||
run: chmod +x YoutubeDownloader/ffmpeg
|
||||
|
||||
- name: Create package
|
||||
# Change into the artifacts directory to avoid including the directory itself in the zip archive
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -8,8 +8,5 @@
|
||||
bin/
|
||||
obj/
|
||||
|
||||
# Avalonia
|
||||
.avalonia-build-tasks/
|
||||
|
||||
# Test results
|
||||
TestResults/
|
||||
TestResults/
|
@ -42,10 +42,6 @@ To learn more about the war and how you can help, [click here](https://tyrrrz.me
|
||||
- 🟢 **[Stable release](https://github.com/Tyrrrz/YoutubeDownloader/releases/latest)**
|
||||
- 🟠 [CI build](https://github.com/Tyrrrz/YoutubeDownloader/actions/workflows/main.yml)
|
||||
|
||||
> **Important**:
|
||||
> To launch the app on MacOS, you need to first remove the downloaded file from quarantine.
|
||||
> You can do that by running the following command in the terminal: `xattr -rd com.apple.quarantine YoutubeDownloader.app`.
|
||||
|
||||
> **Note**:
|
||||
> If you're unsure which build is right for your system, consult with [this page](https://useragent.cc) to determine your OS and CPU architecture.
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Gress;
|
||||
using YoutubeDownloader.Core.Utils;
|
||||
using YoutubeExplode;
|
||||
using YoutubeExplode.Channels;
|
||||
@ -120,4 +122,33 @@ public class QueryResolver(IReadOnlyList<Cookie>? initialCookies = null)
|
||||
?? await TryResolveChannelAsync(query, cancellationToken)
|
||||
?? await ResolveSearchAsync(query, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<QueryResult> ResolveAsync(
|
||||
IReadOnlyList<string> queries,
|
||||
IProgress<Percentage>? progress = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (queries.Count == 1)
|
||||
return await ResolveAsync(queries.Single(), cancellationToken);
|
||||
|
||||
var videos = new List<IVideo>();
|
||||
var videoIds = new HashSet<VideoId>();
|
||||
|
||||
var completed = 0;
|
||||
foreach (var query in queries)
|
||||
{
|
||||
var result = await ResolveAsync(query, cancellationToken);
|
||||
|
||||
foreach (var video in result.Videos)
|
||||
{
|
||||
if (videoIds.Add(video.Id))
|
||||
videos.Add(video);
|
||||
}
|
||||
|
||||
progress?.Report(Percentage.FromFraction(1.0 * ++completed / queries.Count));
|
||||
}
|
||||
|
||||
return new QueryResult(QueryResultKind.Aggregate, $"{queries.Count} queries", videos);
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using YoutubeExplode.Videos;
|
||||
|
||||
namespace YoutubeDownloader.Core.Resolving;
|
||||
|
||||
public record QueryResult(QueryResultKind Kind, string Title, IReadOnlyList<IVideo> Videos)
|
||||
{
|
||||
public static QueryResult Aggregate(IReadOnlyList<QueryResult> results)
|
||||
{
|
||||
if (!results.Any())
|
||||
throw new ArgumentException("Cannot aggregate empty results.", nameof(results));
|
||||
|
||||
return new QueryResult(
|
||||
// Single query -> inherit kind, multiple queries -> aggregate
|
||||
results.Count == 1
|
||||
? results.Single().Kind
|
||||
: QueryResultKind.Aggregate,
|
||||
// Single query -> inherit title, multiple queries -> aggregate
|
||||
results.Count == 1
|
||||
? results.Single().Title
|
||||
: $"{results.Count} queries",
|
||||
// Combine all videos, deduplicate by ID
|
||||
results.SelectMany(q => q.Videos).DistinctBy(v => v.Id).ToArray()
|
||||
);
|
||||
}
|
||||
}
|
||||
public record QueryResult(QueryResultKind Kind, string Title, IReadOnlyList<IVideo> Videos);
|
||||
|
@ -1,10 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CSharpier.MsBuild" Version="1.0.2" PrivateAssets="all" />
|
||||
<PackageReference Include="CSharpier.MsBuild" Version="0.30.6" PrivateAssets="all" />
|
||||
<PackageReference Include="Gress" Version="2.1.1" />
|
||||
<PackageReference Include="JsonExtensions" Version="1.2.0" />
|
||||
<PackageReference Include="TagLibSharp" Version="2.3.0" />
|
||||
<PackageReference Include="YoutubeExplode" Version="6.5.4" />
|
||||
<PackageReference Include="YoutubeExplode.Converter" Version="6.5.4" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
</Project>
|
@ -5,7 +5,7 @@ VisualStudioVersion = 17.7.33920.267
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YoutubeDownloader", "YoutubeDownloader\YoutubeDownloader.csproj", "{AF6D645E-DDDD-4034-B644-D5328CC893C1}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{131C2561-E5A1-43E8-BF38-40E2E23DB0A4}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{131C2561-E5A1-43E8-BF38-40E2E23DB0A4}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Directory.Build.props = Directory.Build.props
|
||||
License.txt = License.txt
|
||||
|
@ -8,7 +8,6 @@
|
||||
xmlns:materialControls="clr-namespace:Material.Styles.Controls;assembly=Material.Styles"
|
||||
xmlns:materialIcons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||
xmlns:materialStyles="clr-namespace:Material.Styles.Themes;assembly=Material.Styles"
|
||||
Name="YoutubeDownloader"
|
||||
ActualThemeVariantChanged="Application_OnActualThemeVariantChanged">
|
||||
<Application.DataTemplates>
|
||||
<framework:ViewManager />
|
||||
|
@ -46,7 +46,7 @@ if (Test-Path $OutputPath) {
|
||||
Write-Host "Downloading FFmpeg for $Platform..."
|
||||
$http = New-Object System.Net.WebClient
|
||||
try {
|
||||
$http.DownloadFile("https://github.com/Tyrrrz/FFmpegBin/releases/download/7.1.1/ffmpeg-$Platform.zip", "$OutputPath.zip")
|
||||
$http.DownloadFile("https://github.com/Tyrrrz/FFmpegBin/releases/download/7.0/ffmpeg-$Platform.zip", "$OutputPath.zip")
|
||||
} finally {
|
||||
$http.Dispose()
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ public class DialogManager : IDisposable
|
||||
}
|
||||
);
|
||||
|
||||
return file?.TryGetLocalPath() ?? file?.Path.ToString();
|
||||
return file?.Path.LocalPath;
|
||||
}
|
||||
|
||||
public async Task<string?> PromptDirectoryPathAsync(string defaultDirPath = "")
|
||||
@ -74,21 +74,19 @@ public class DialogManager : IDisposable
|
||||
Application.Current?.ApplicationLifetime?.TryGetTopLevel()
|
||||
?? throw new ApplicationException("Could not find the top-level visual element.");
|
||||
|
||||
var result = await topLevel.StorageProvider.OpenFolderPickerAsync(
|
||||
var startLocation = await topLevel.StorageProvider.TryGetFolderFromPathAsync(
|
||||
defaultDirPath
|
||||
);
|
||||
|
||||
var folderPickResult = await topLevel.StorageProvider.OpenFolderPickerAsync(
|
||||
new FolderPickerOpenOptions
|
||||
{
|
||||
AllowMultiple = false,
|
||||
SuggestedStartLocation = await topLevel.StorageProvider.TryGetFolderFromPathAsync(
|
||||
defaultDirPath
|
||||
),
|
||||
SuggestedStartLocation = startLocation,
|
||||
}
|
||||
);
|
||||
|
||||
var directory = result.FirstOrDefault();
|
||||
if (directory is null)
|
||||
return null;
|
||||
|
||||
return directory.TryGetLocalPath() ?? directory.Path.ToString();
|
||||
return folderPickResult.FirstOrDefault()?.Path.LocalPath;
|
||||
}
|
||||
|
||||
public void Dispose() => _dialogLock.Dispose();
|
||||
|
@ -1,87 +0,0 @@
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$PublishDirPath,
|
||||
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$IconsFilePath,
|
||||
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$FullVersion,
|
||||
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$ShortVersion
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Setup paths
|
||||
$tempDirPath = Join-Path $PublishDirPath "../publish-macos-app-temp"
|
||||
$bundleName = "YoutubeDownloader.app"
|
||||
$bundleDirPath = Join-Path $tempDirPath $bundleName
|
||||
$contentsDirPath = Join-Path $bundleDirPath "Contents"
|
||||
$macosDirPath = Join-Path $contentsDirPath "MacOS"
|
||||
$resourcesDirPath = Join-Path $contentsDirPath "Resources"
|
||||
|
||||
try {
|
||||
# Initialize the bundle's directory structure
|
||||
New-Item -Path $bundleDirPath -ItemType Directory -Force
|
||||
New-Item -Path $contentsDirPath -ItemType Directory -Force
|
||||
New-Item -Path $macosDirPath -ItemType Directory -Force
|
||||
New-Item -Path $resourcesDirPath -ItemType Directory -Force
|
||||
|
||||
# Copy icons into the .app's Resources folder
|
||||
Copy-Item -Path $IconsFilePath -Destination (Join-Path $resourcesDirPath "AppIcon.icns") -Force
|
||||
|
||||
# Generate the Info.plist metadata file with the app information
|
||||
$plistContent = @"
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>YoutubeDownloader</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>YoutubeDownloader</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>YoutubeDownloader</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>© Oleksii Holub</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>me.Tyrrrz.YoutubeDownloader</string>
|
||||
<key>CFBundleSpokenName</key>
|
||||
<string>YoutubeDownloader</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>AppIcon</string>
|
||||
<key>CFBundleIconName</key>
|
||||
<string>AppIcon</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$FullVersion</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$ShortVersion</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true />
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
</dict>
|
||||
</plist>
|
||||
"@
|
||||
|
||||
Set-Content -Path (Join-Path $contentsDirPath "Info.plist") -Value $plistContent
|
||||
|
||||
# Delete the previous bundle if it exists
|
||||
if (Test-Path (Join-Path $PublishDirPath $bundleName)) {
|
||||
Remove-Item -Path (Join-Path $PublishDirPath $bundleName) -Recurse -Force
|
||||
}
|
||||
|
||||
# Move all files from the publish directory into the MacOS directory
|
||||
Get-ChildItem -Path $PublishDirPath | ForEach-Object {
|
||||
Move-Item -Path $_.FullName -Destination $macosDirPath -Force
|
||||
}
|
||||
|
||||
# Move the final bundle into the publish directory for upload
|
||||
Move-Item -Path $bundleDirPath -Destination $PublishDirPath -Force
|
||||
}
|
||||
finally {
|
||||
# Clean up the temporary directory
|
||||
Remove-Item -Path $tempDirPath -Recurse -Force
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@ -22,7 +21,6 @@ namespace YoutubeDownloader.ViewModels.Components;
|
||||
public partial class DashboardViewModel : ViewModelBase
|
||||
{
|
||||
private readonly ViewModelManager _viewModelManager;
|
||||
private readonly SnackbarManager _snackbarManager;
|
||||
private readonly DialogManager _dialogManager;
|
||||
private readonly SettingsService _settingsService;
|
||||
|
||||
@ -30,15 +28,24 @@ public partial class DashboardViewModel : ViewModelBase
|
||||
private readonly ResizableSemaphore _downloadSemaphore = new();
|
||||
private readonly AutoResetProgressMuxer _progressMuxer;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(IsProgressIndeterminate))]
|
||||
[NotifyCanExecuteChangedFor(nameof(ProcessQueryCommand))]
|
||||
[NotifyCanExecuteChangedFor(nameof(ShowAuthSetupCommand))]
|
||||
[NotifyCanExecuteChangedFor(nameof(ShowSettingsCommand))]
|
||||
public partial bool IsBusy { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(ProcessQueryCommand))]
|
||||
public partial string? Query { get; set; }
|
||||
|
||||
public DashboardViewModel(
|
||||
ViewModelManager viewModelManager,
|
||||
SnackbarManager snackbarManager,
|
||||
DialogManager dialogManager,
|
||||
SettingsService settingsService
|
||||
)
|
||||
{
|
||||
_viewModelManager = viewModelManager;
|
||||
_snackbarManager = snackbarManager;
|
||||
_dialogManager = dialogManager;
|
||||
_settingsService = settingsService;
|
||||
|
||||
@ -60,23 +67,12 @@ public partial class DashboardViewModel : ViewModelBase
|
||||
);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(IsProgressIndeterminate))]
|
||||
[NotifyCanExecuteChangedFor(nameof(ProcessQueryCommand))]
|
||||
[NotifyCanExecuteChangedFor(nameof(ShowAuthSetupCommand))]
|
||||
[NotifyCanExecuteChangedFor(nameof(ShowSettingsCommand))]
|
||||
public partial bool IsBusy { get; set; }
|
||||
|
||||
public ProgressContainer<Percentage> Progress { get; } = new();
|
||||
|
||||
public bool IsProgressIndeterminate => IsBusy && Progress.Current.Fraction is <= 0 or >= 1;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(ProcessQueryCommand))]
|
||||
public partial string? Query { get; set; }
|
||||
|
||||
public ObservableCollection<DownloadViewModel> Downloads { get; } = [];
|
||||
|
||||
public bool IsProgressIndeterminate => IsBusy && Progress.Current.Fraction is <= 0 or >= 1;
|
||||
|
||||
private bool CanShowAuthSetup() => !IsBusy;
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanShowAuthSetup))]
|
||||
@ -183,41 +179,18 @@ public partial class DashboardViewModel : ViewModelBase
|
||||
var resolver = new QueryResolver(_settingsService.LastAuthCookies);
|
||||
var downloader = new VideoDownloader(_settingsService.LastAuthCookies);
|
||||
|
||||
// Split queries by newlines
|
||||
var queries = Query.Split(
|
||||
'\n',
|
||||
StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries
|
||||
var result = await resolver.ResolveAsync(
|
||||
Query.Split(
|
||||
"\n",
|
||||
StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries
|
||||
),
|
||||
progress
|
||||
);
|
||||
|
||||
// Process individual queries
|
||||
var queryResults = new List<QueryResult>();
|
||||
foreach (var (i, query) in queries.Index())
|
||||
// Single video
|
||||
if (result.Videos.Count == 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
queryResults.Add(await resolver.ResolveAsync(query));
|
||||
}
|
||||
// If it's not the only query in the list, don't interrupt the process
|
||||
// and report the error via an async notification instead of a sync dialog.
|
||||
// https://github.com/Tyrrrz/YoutubeDownloader/issues/563
|
||||
catch (YoutubeExplodeException ex)
|
||||
when (ex is VideoUnavailableException or PlaylistUnavailableException
|
||||
&& queries.Length > 1
|
||||
)
|
||||
{
|
||||
_snackbarManager.Notify(ex.Message);
|
||||
}
|
||||
|
||||
progress.Report(Percentage.FromFraction((i + 1.0) / queries.Length));
|
||||
}
|
||||
|
||||
// Aggregate results
|
||||
var queryResult = QueryResult.Aggregate(queryResults);
|
||||
|
||||
// Single video result
|
||||
if (queryResult.Videos.Count == 1)
|
||||
{
|
||||
var video = queryResult.Videos.Single();
|
||||
var video = result.Videos.Single();
|
||||
|
||||
var downloadOptions = await downloader.GetDownloadOptionsAsync(
|
||||
video.Id,
|
||||
@ -236,14 +209,14 @@ public partial class DashboardViewModel : ViewModelBase
|
||||
Query = "";
|
||||
}
|
||||
// Multiple videos
|
||||
else if (queryResult.Videos.Count > 1)
|
||||
else if (result.Videos.Count > 1)
|
||||
{
|
||||
var downloads = await _dialogManager.ShowDialogAsync(
|
||||
_viewModelManager.CreateDownloadMultipleSetupViewModel(
|
||||
queryResult.Title,
|
||||
queryResult.Videos,
|
||||
result.Title,
|
||||
result.Videos,
|
||||
// Pre-select videos if they come from a single query and not from search
|
||||
queryResult.Kind
|
||||
result.Kind
|
||||
is not QueryResultKind.Search
|
||||
and not QueryResultKind.Aggregate
|
||||
)
|
||||
|
@ -62,9 +62,7 @@ public partial class MainViewModel(
|
||||
$"""
|
||||
You're using a development build of {Program.Name}. These builds are not thoroughly tested and may contain bugs.
|
||||
|
||||
Auto-updates are disabled for development builds.
|
||||
|
||||
Click SEE RELEASES if you want to download a stable release instead.
|
||||
Auto-updates are disabled for development builds. If you want to switch to a stable release, please download it manually.
|
||||
""",
|
||||
"SEE RELEASES",
|
||||
"CLOSE"
|
||||
@ -84,7 +82,7 @@ public partial class MainViewModel(
|
||||
$"""
|
||||
FFmpeg is required for {Program.Name} to work. Please download it and make it available in the application directory or on the system PATH.
|
||||
|
||||
Alternatively, you can also download a version of {Program.Name} that has FFmpeg bundled with it. Look for release assets that are NOT marked as *.Bare.
|
||||
Alternatively, you can also download a version of {Program.Name} that has FFmpeg bundled with it.
|
||||
|
||||
Click DOWNLOAD to go to the FFmpeg download page.
|
||||
""",
|
||||
|
@ -137,7 +137,7 @@
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
IsVisible="{Binding !!Downloads.Count}"
|
||||
ItemsSource="{Binding Downloads}"
|
||||
VerticalScrollBarVisibility="Visible">
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Command="{Binding RemoveSuccessfulDownloadsCommand}" Header="Remove successful downloads" />
|
||||
|
@ -20,7 +20,7 @@
|
||||
CloseOnClickAway="False"
|
||||
DisableOpeningAnimation="True"
|
||||
Loaded="DialogHost_OnLoaded">
|
||||
<materialStyles:SnackbarHost HostName="Root" SnackbarMaxCounts="3">
|
||||
<materialStyles:SnackbarHost HostName="Root">
|
||||
<ContentControl Content="{Binding Dashboard}" />
|
||||
</materialStyles:SnackbarHost>
|
||||
</dialogHostAvalonia:DialogHost>
|
||||
|
@ -1,4 +1,5 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<ApplicationIcon>..\favicon.ico</ApplicationIcon>
|
||||
@ -10,33 +11,29 @@
|
||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<DownloadFFmpeg>true</DownloadFFmpeg>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AvaloniaResource Include="..\favicon.ico" Link="favicon.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None
|
||||
Include="ffmpeg.exe"
|
||||
CopyToOutputDirectory="PreserveNewest"
|
||||
Condition="Exists('ffmpeg.exe')"
|
||||
/>
|
||||
<None Include="ffmpeg.exe" CopyToOutputDirectory="PreserveNewest" Condition="Exists('ffmpeg.exe')" />
|
||||
<None Include="ffmpeg" CopyToOutputDirectory="PreserveNewest" Condition="Exists('ffmpeg')" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AsyncImageLoader.Avalonia" Version="3.3.0" />
|
||||
<PackageReference Include="Avalonia" Version="11.3.0" />
|
||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.3.0" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.3.0" />
|
||||
<PackageReference
|
||||
Include="Avalonia.Diagnostics"
|
||||
Version="11.3.0"
|
||||
Condition="'$(Configuration)' == 'Debug'"
|
||||
/>
|
||||
<PackageReference Include="Avalonia" Version="11.2.6" />
|
||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.2.6" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.2.6" />
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.2.6" Condition="'$(Configuration)' == 'Debug'" />
|
||||
<PackageReference Include="Cogwheel" Version="2.1.0" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="CSharpier.MsBuild" Version="1.0.2" PrivateAssets="all" />
|
||||
<PackageReference Include="CSharpier.MsBuild" Version="0.30.6" PrivateAssets="all" />
|
||||
<PackageReference Include="Deorcify" Version="1.1.0" PrivateAssets="all" />
|
||||
<PackageReference Include="DialogHost.Avalonia" Version="0.9.2" />
|
||||
<PackageReference Include="Gress" Version="2.1.1" />
|
||||
@ -48,9 +45,11 @@
|
||||
<PackageReference Include="WebView.Avalonia" Version="11.0.0.1" />
|
||||
<PackageReference Include="WebView.Avalonia.Desktop" Version="11.0.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\YoutubeDownloader.Core\YoutubeDownloader.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Avalonia.WebView is completely incompatible with trimming -->
|
||||
<ItemGroup>
|
||||
<TrimmerRootAssembly Include="Avalonia.WebView" />
|
||||
@ -64,26 +63,10 @@
|
||||
<TrimmerRootAssembly Include="WebView.Avalonia" />
|
||||
<TrimmerRootAssembly Include="WebView.Core" />
|
||||
</ItemGroup>
|
||||
<Target
|
||||
Name="DownloadFFmpeg"
|
||||
BeforeTargets="Restore;PreBuildEvent"
|
||||
Condition="$(DownloadFFmpeg) AND !Exists('ffmpeg.exe') AND !Exists('ffmpeg')"
|
||||
>
|
||||
<Exec
|
||||
Command="pwsh -ExecutionPolicy Bypass -File $(ProjectDir)/Download-FFmpeg.ps1 -Platform $(RuntimeIdentifier) -OutputPath $(ProjectDir)"
|
||||
LogStandardErrorAsError="true"
|
||||
Condition="'$(RuntimeIdentifier)' != ''"
|
||||
/>
|
||||
<Exec
|
||||
Command="pwsh -ExecutionPolicy Bypass -File $(ProjectDir)/Download-FFmpeg.ps1 -OutputPath $(ProjectDir)"
|
||||
LogStandardErrorAsError="true"
|
||||
Condition="'$(RuntimeIdentifier)' == ''"
|
||||
/>
|
||||
|
||||
<Target Name="DownloadFFmpeg" BeforeTargets="Restore;PreBuildEvent" Condition="$(DownloadFFmpeg) AND !Exists('ffmpeg.exe') AND !Exists('ffmpeg')">
|
||||
<Exec Command="pwsh -ExecutionPolicy Bypass -File $(ProjectDir)/Download-FFmpeg.ps1 -Platform $(RuntimeIdentifier) -OutputPath $(ProjectDir)" LogStandardErrorAsError="true" Condition="'$(RuntimeIdentifier)' != ''" />
|
||||
<Exec Command="pwsh -ExecutionPolicy Bypass -File $(ProjectDir)/Download-FFmpeg.ps1 -OutputPath $(ProjectDir)" LogStandardErrorAsError="true" Condition="'$(RuntimeIdentifier)' == ''" />
|
||||
</Target>
|
||||
<Target Name="PublishMacOSBundle" AfterTargets="Publish" Condition="$(PublishMacOSBundle)">
|
||||
<Exec
|
||||
Command="pwsh -ExecutionPolicy Bypass -File $(ProjectDir)/Publish-MacOSBundle.ps1 -PublishDirPath $(PublishDir) -IconsFilePath $(ProjectDir)/../favicon.icns -FullVersion $(Version) -ShortVersion $(AssemblyVersion)"
|
||||
LogStandardErrorAsError="true"
|
||||
/>
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
</Project>
|
BIN
favicon.icns
BIN
favicon.icns
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user