Skip to content

Commit

Permalink
Merge YoutubeExplode.Converter inside the core repo
Browse files Browse the repository at this point in the history
  • Loading branch information
Tyrrrz committed Aug 29, 2021
1 parent 0f50f7d commit f3b0762
Show file tree
Hide file tree
Showing 25 changed files with 995 additions and 27 deletions.
5 changes: 1 addition & 4 deletions .github/ISSUE_TEMPLATE/config.yml
Expand Up @@ -8,7 +8,4 @@ contact_links:
about: Chat with the project community.
- name: 🗨 Discussions
url: https://github.com/Tyrrrz/YoutubeExplode/discussions/new
about: Ask and answer questions.
- name: 🔗 YoutubeExplode.Converter Issues
url: https://github.com/Tyrrrz/YoutubeExplode.Converter/issues
about: File issues related to YoutubeExplode.Converter in its dedicated repository.
about: Ask and answer questions.
8 changes: 5 additions & 3 deletions .github/workflows/CD.yml
Expand Up @@ -23,10 +23,12 @@ jobs:
dotnet-version: 5.0.x

- name: Pack
run: dotnet pack YoutubeExplode --configuration Release
run: dotnet pack --configuration Release

- name: Deploy
run: dotnet nuget push YoutubeExplode\bin\Release\*.nupkg -s nuget.org -k ${{ secrets.NUGET_TOKEN }}
run: |
dotnet nuget push YoutubeExplode\bin\Release\*.nupkg -s nuget.org -k ${{ secrets.NUGET_TOKEN }}
dotnet nuget push YoutubeExplode.Converter\bin\Release\*.nupkg -s nuget.org -k ${{ secrets.NUGET_TOKEN }}
- name: Notify Discord
uses: satak/webrequest-action@v1.2.4
Expand All @@ -40,4 +42,4 @@ jobs:
payload: |
{
"content": "**YoutubeExplode** new version released!\nVersion: `${{ steps.get-version.outputs.tag }}`\nChangelog: <https://github.com/Tyrrrz/YoutubeExplode/blob/${{ steps.get-version.outputs.tag }}/Changelog.md>"
}
}
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Expand Up @@ -29,4 +29,4 @@ jobs:
- name: Upload coverage
uses: codecov/codecov-action@v1.0.5
with:
token: ${{ secrets.CODECOV_TOKEN }}
token: ${{ secrets.CODECOV_TOKEN }}
21 changes: 20 additions & 1 deletion Directory.Build.props
Expand Up @@ -9,9 +9,28 @@
<WarningsAsErrors>nullable</WarningsAsErrors>
</PropertyGroup>

<!-- Disable nullability warnings on older frameworks because there is no nullability info for BCL -->
<!-- Disable nullability warnings on frameworks where BCL is not annotated -->
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'net461'">
<Nullable>annotations</Nullable>
</PropertyGroup>

<PropertyGroup>
<Authors>$(Company)</Authors>
<PackageTags>youtube video download playlist user channel closed caption tracks subtitles parse extract metadata info net core standard</PackageTags>
<PackageProjectUrl>https://github.com/Tyrrrz/YoutubeExplode</PackageProjectUrl>
<PackageReleaseNotes>https://github.com/Tyrrrz/YoutubeExplode/blob/master/Changelog.md</PackageReleaseNotes>
<PackageReadmeFile>ReadMe.md</PackageReadmeFile>
<PackageIcon>favicon.png</PackageIcon>
<PackageLicenseExpression>LGPL-3.0-only</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<DebugType>embedded</DebugType>
</PropertyGroup>

<ItemGroup>
<None Include="../ReadMe.md" Pack="true" PackagePath="" Visible="false" />
<None Include="../favicon.png" Pack="true" PackagePath="" Visible="false" />
</ItemGroup>

</Project>
4 changes: 2 additions & 2 deletions License.txt
@@ -1,5 +1,5 @@
YoutubeExplode
Copyright (C) 2016-2020 Alexey Golub
Copyright (C) 2016-2021 Alexey Golub

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
Expand Down Expand Up @@ -857,4 +857,4 @@ into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
81 changes: 81 additions & 0 deletions YoutubeExplode.Converter.Tests/Fixtures/FFmpegFixture.cs
@@ -0,0 +1,81 @@
using System;
using System.IO;
using System.IO.Compression;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using CliWrap;
using Xunit;

namespace YoutubeExplode.Converter.Tests.Fixtures
{
public partial class FFmpegFixture : IAsyncLifetime
{
public string FilePath => Path.Combine(
Path.GetDirectoryName(typeof(FFmpegFixture).Assembly.Location) ?? Directory.GetCurrentDirectory(),
GetFFmpegFileName()
);

private async ValueTask EnsureFFmpegHasExecutePermissionAsync()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return;

await Cli.Wrap("/bin/bash")
.WithArguments(new[] {"-c", $"chmod +x {FilePath}"})
.ExecuteAsync();
}

private async ValueTask DownloadFFmpegAsync()
{
using var httpClient = new HttpClient();

await using var zipStream = await httpClient.GetStreamAsync(GetFFmpegDownloadUrl());
using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);

var entry = zip.GetEntry(GetFFmpegFileName());

if (entry is null)
throw new FileNotFoundException("Downloaded archive doesn't contain FFmpeg.");

await using var entryStream = entry.Open();
await using var fileStream = File.Create(FilePath);
await entryStream.CopyToAsync(fileStream);

await EnsureFFmpegHasExecutePermissionAsync();
}

public async Task InitializeAsync()
{
// Don't re-download FFmpeg from last time
if (File.Exists(FilePath))
return;

await DownloadFFmpegAsync();
}

public Task DisposeAsync() => Task.CompletedTask;
}

public partial class FFmpegFixture
{
private static string GetFFmpegFileName() =>
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? "ffmpeg.exe"
: "ffmpeg";

private static string GetFFmpegDownloadUrl()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return "https://github.com/vot/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-win-64.zip";

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return "https://github.com/vot/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-linux-64.zip";

if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return "https://github.com/vot/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-osx-64.zip";

throw new InvalidOperationException("Unknown OS.");
}
}
}
25 changes: 25 additions & 0 deletions YoutubeExplode.Converter.Tests/Fixtures/TempOutputFixture.cs
@@ -0,0 +1,25 @@
using System;
using System.IO;

namespace YoutubeExplode.Converter.Tests.Fixtures
{
public class TempOutputFixture : IDisposable
{
public string DirPath => Path.Combine(
Path.GetDirectoryName(typeof(TempOutputFixture).Assembly.Location) ?? Directory.GetCurrentDirectory(),
"Temp"
);

public TempOutputFixture() => Directory.CreateDirectory(DirPath);

public string GetTempFilePath(string fileName) => Path.Combine(DirPath, fileName);

public string GetTempFilePath() => GetTempFilePath(Guid.NewGuid().ToString());

public void Dispose()
{
if (Directory.Exists(DirPath))
Directory.Delete(DirPath, true);
}
}
}
141 changes: 141 additions & 0 deletions YoutubeExplode.Converter.Tests/GeneralSpecs.cs
@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using FluentAssertions;
using Xunit;
using Xunit.Abstractions;
using YoutubeExplode.Converter.Tests.Fixtures;

namespace YoutubeExplode.Converter.Tests
{
public class GeneralSpecs : IClassFixture<TempOutputFixture>, IClassFixture<FFmpegFixture>
{
private readonly ITestOutputHelper _testOutput;
private readonly TempOutputFixture _tempOutputFixture;
private readonly FFmpegFixture _ffmpegFixture;

public GeneralSpecs(
ITestOutputHelper testOutput,
TempOutputFixture tempOutputFixture,
FFmpegFixture ffmpegFixture)
{
_testOutput = testOutput;
_tempOutputFixture = tempOutputFixture;
_ffmpegFixture = ffmpegFixture;
}

[Fact]
public async Task User_can_download_a_video_by_merging_best_streams_into_a_single_mp4_file()
{
// Arrange
var youtube = new YoutubeClient();
var outputFilePath = Path.ChangeExtension(_tempOutputFixture.GetTempFilePath(), "mp4");

// Act
await youtube.Videos.DownloadAsync("AI7ULzgf8RU", outputFilePath);

var fileInfo = new FileInfo(outputFilePath);

// Assert
fileInfo.Exists.Should().BeTrue();
fileInfo.Length.Should().BeGreaterThan(0);
}

[Fact]
public async Task User_can_download_a_video_by_merging_best_streams_into_a_single_webm_file()
{
// Arrange
var youtube = new YoutubeClient();
var outputFilePath = Path.ChangeExtension(_tempOutputFixture.GetTempFilePath(), "webm");

// Act
await youtube.Videos.DownloadAsync("FkklG9MA0vM", outputFilePath);

var fileInfo = new FileInfo(outputFilePath);

// Assert
fileInfo.Exists.Should().BeTrue();
fileInfo.Length.Should().BeGreaterThan(0);
}

[Fact]
public async Task User_can_download_a_video_by_merging_best_streams_into_a_single_mp3_file()
{
// Arrange
var youtube = new YoutubeClient();
var outputFilePath = Path.ChangeExtension(_tempOutputFixture.GetTempFilePath(), "mp3");

// Act
await youtube.Videos.DownloadAsync("AI7ULzgf8RU", outputFilePath);

var fileInfo = new FileInfo(outputFilePath);

// Assert
fileInfo.Exists.Should().BeTrue();
fileInfo.Length.Should().BeGreaterThan(0);
}

[Fact]
public async Task User_can_download_a_video_by_merging_best_streams_into_a_single_ogg_file()
{
// Arrange
var youtube = new YoutubeClient();
var outputFilePath = Path.ChangeExtension(_tempOutputFixture.GetTempFilePath(), "ogg");

// Act
await youtube.Videos.DownloadAsync("AI7ULzgf8RU", outputFilePath);

var fileInfo = new FileInfo(outputFilePath);

// Assert
fileInfo.Exists.Should().BeTrue();
fileInfo.Length.Should().BeGreaterThan(0);
}

[Fact]
public async Task User_can_download_a_video_with_custom_conversion_settings()
{
// Arrange
var youtube = new YoutubeClient();
var outputFilePath = _tempOutputFixture.GetTempFilePath();

// Act
await youtube.Videos.DownloadAsync(
"AI7ULzgf8RU", outputFilePath,
o => o
.SetFFmpegPath(_ffmpegFixture.FilePath)
.SetFormat("mp4")
.SetPreset(ConversionPreset.UltraFast)
);

var fileInfo = new FileInfo(outputFilePath);

// Assert
fileInfo.Exists.Should().BeTrue();
fileInfo.Length.Should().BeGreaterThan(0);
}

[Fact]
public async Task User_can_download_a_video_and_track_the_progress_of_the_operation()
{
// Arrange
var progressReports = new List<double>();
var progress = new Progress<double>(p =>
{
_testOutput.WriteLine($"Progress: {p:P2}");
progressReports.Add(p);
});

var youtube = new YoutubeClient();
var outputFilePath = _tempOutputFixture.GetTempFilePath();

// Act
await youtube.Videos.DownloadAsync("AI7ULzgf8RU", outputFilePath, progress);

// Assert
progressReports.Should().NotBeEmpty();
progressReports.Should().Contain(1.0);
}
}
}
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<CollectCoverage>true</CollectCoverage>
<CoverletOutputFormat>opencover</CoverletOutputFormat>
</PropertyGroup>

<ItemGroup>
<Content Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="CliWrap" Version="3.3.2" />
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="GitHubActionsTestLogger" Version="1.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" PrivateAssets="all" />
<PackageReference Include="coverlet.msbuild" Version="3.0.3" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\YoutubeExplode.Converter\YoutubeExplode.Converter.csproj" />
</ItemGroup>

</Project>
5 changes: 5 additions & 0 deletions YoutubeExplode.Converter.Tests/xunit.runner.json
@@ -0,0 +1,5 @@
{
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
"methodDisplayOptions": "all",
"methodDisplay": "method"
}

0 comments on commit f3b0762

Please sign in to comment.