Skip to content

Commit

Permalink
merge hotfix 6.3.10
Browse files Browse the repository at this point in the history
  • Loading branch information
tmm360 committed Mar 23, 2024
2 parents 7083a7c + 442d8c4 commit 2c13f67
Show file tree
Hide file tree
Showing 110 changed files with 1,115 additions and 1,551 deletions.
23 changes: 6 additions & 17 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,23 +1,12 @@
# User-specific files
.vs/
.idea/
*.suo
*.user
*.userosscache
*.sln.docstates

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
[Xx]64/
[Xx]86/
[Bb]uild/
bld/
[Bb]in/
[Oo]bj/

# Coverage
*.opencover.xml
bin/
obj/

#Visual studio cache/options directory
.vs/
# Test results
TestResults/
10 changes: 9 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ https://github.com/Etherna/YoutubeExplode/releases

# Changelog

> **Important**:
> This changelog is no longer maintained and will be removed in the future.
> Going forward, new versions of this package will have the corresponding release notes published on [GitHub Releases](https://github.com/Tyrrrz/YoutubeExplode/releases).
## v6.3.8 (23-Nov-2023)

- [Converter] Fixed an issue where downloading subtitled videos with `VideoClient.DownloadAsync(...)` crashed with an exception for certain language codes.

## v6.3.7 (09-Nov-2023)

- [Converter] Fixed an issue where subtitles embedded via `VideoClient.DownloadAsync(...)` had their languages specified using ISO 639-1 codes instead of ISO 639-2 codes.
Expand Down Expand Up @@ -573,4 +581,4 @@ Thanks to [@d4n3436](https://github.com/d4n3436), [@Benjamin K.](https://github.
- Fixed other issues that prevented the library from being usable due to YouTube changes.
- Added dependency on `Newtonsoft.Json` and `AngleSharp`.

This version has a lot of breaking changes and the migration isn't very straightforward. The readme has been updated with new usage examples and demo projects have been changed to work with new API.
This version has a lot of breaking changes and the migration isn't very straightforward. The readme has been updated with new usage examples and demo projects have been changed to work with new API.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
MIT License

YoutubeExplode
Copyright (C) 2016-2023 Oleksii Holub
Copyright (c) 2016-2024 Oleksii Holub

Etherna YoutubeDownloader fork
Copyright (C) 2023-present Etherna SA
Expand Down
21 changes: 12 additions & 9 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@ For questions or problems please write an email to [info@etherna.io](mailto:info
**YoutubeExplode** is a library that provides an interface to query metadata of YouTube videos, playlists and channels, as well as to resolve and download video streams and closed caption tracks.
Behind a layer of abstraction, this library works by scraping raw page data and exploiting reverse-engineered internal endpoints.

> 📝 Want to learn more about how YouTube works under the hood?
> [Read this article](https://tyrrrz.me/blog/reverse-engineering-youtube-revisited).
> 📝 Interested in the inner workings of this library?
> See the [Reverse-Engineering YouTube](https://tyrrrz.me/blog/reverse-engineering-youtube-revisited) article.
**Extension packages**:

- [YoutubeExplode.Converter](YoutubeExplode.Converter) — provides an interface to download and convert videos using FFmpeg

## Install

Expand Down Expand Up @@ -124,7 +128,7 @@ await youtube.Videos.Streams.DownloadAsync(streamInfo, $"video.{streamInfo.Conta

> **Warning**:
> While the `Url` property in the stream metadata can be used to access the underlying content, you need a series of carefully crafted HTTP requests in order to do so.
> It's highly recommended to use `Videos.Streams.GetAsync(...)` or `Videos.Streams.DownloadAsync(...)` instead, as they will all the heavy lifting for you.
> It's highly recommended to use `Videos.Streams.GetAsync(...)` or `Videos.Streams.DownloadAsync(...)` instead, as they will perform all the heavy lifting for you.
#### Downloading closed captions

Expand Down Expand Up @@ -239,6 +243,10 @@ await foreach (var batch in youtube.Playlists.GetVideoBatchesAsync(playlistUrl))
}
```

> **Note**:
> You can craft playlist IDs to fetch special auto-generated playlists, such as music mixes, popular channel uploads, liked videos, and more.
> See [this reference](https://wiki.archiveteam.org/index.php/YouTube/Technical_details#Playlists) for more information.
### Channels

#### Retrieving channel metadata
Expand Down Expand Up @@ -410,9 +418,4 @@ In order to actually perform the authentication, you can use an embedded browser

## Etymology

The "Explode" in **YoutubeExplode** comes from the name of a PHP function that splits up strings, [`explode(...)`](https://php.net/manual/en/function.explode.php). When I was starting the development of this library, most of the reference source code I read was written in PHP, hence the inspiration for the name.

## Related projects

- [**YoutubeExplode.Converter**](YoutubeExplode.Converter) — provides capabilities for downloading YouTube videos with conversion to other formats, using FFmpeg.
- [**YoutubeDownloader**](https://github.com/Tyrrrz/YoutubeDownloader) — desktop application for downloading YouTube videos, based on **YoutubeExplode**.
The "Explode" in **YoutubeExplode** comes from the name of a PHP function that splits up strings, [`explode(...)`](https://php.net/manual/en/function.explode.php). When I was starting the development of this library, most of the reference source code I read was written in PHP, hence the inspiration for the name.
73 changes: 45 additions & 28 deletions YoutubeDownloader.Converter.Tests/GeneralSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,8 @@

namespace YoutubeExplode.Converter.Tests;

public class GeneralSpecs : IAsyncLifetime
public class GeneralSpecs(ITestOutputHelper testOutput) : IAsyncLifetime
{
private readonly ITestOutputHelper _testOutput;

public GeneralSpecs(ITestOutputHelper testOutput) => _testOutput = testOutput;

public async Task InitializeAsync() => await FFmpeg.InitializeAsync();

public Task DisposeAsync() => Task.CompletedTask;
Expand Down Expand Up @@ -113,12 +109,10 @@ public async Task I_can_download_a_video_as_a_single_mp4_file_with_multiple_stre
.Take(3)
.ToArray();

await youtube
.Videos
.DownloadAsync(
videoStreamInfos.Concat<IStreamInfo>(audioStreamInfos).ToArray(),
new ConversionRequestBuilder(filePath).Build()
);
await youtube.Videos.DownloadAsync(
videoStreamInfos.Concat<IStreamInfo>(audioStreamInfos).ToArray(),
new ConversionRequestBuilder(filePath).Build()
);

// Assert
MediaFormat.IsMp4File(filePath).Should().BeTrue();
Expand Down Expand Up @@ -159,12 +153,10 @@ public async Task I_can_download_a_video_as_a_single_webm_file_with_multiple_str
.Take(3)
.ToArray();

await youtube
.Videos
.DownloadAsync(
videoStreamInfos.Concat<IStreamInfo>(audioStreamInfos).ToArray(),
new ConversionRequestBuilder(filePath).Build()
);
await youtube.Videos.DownloadAsync(
videoStreamInfos.Concat<IStreamInfo>(audioStreamInfos).ToArray(),
new ConversionRequestBuilder(filePath).Build()
);

// Assert
MediaFormat.IsWebMFile(filePath).Should().BeTrue();
Expand All @@ -188,21 +180,46 @@ public async Task I_can_download_a_video_using_custom_conversion_settings()
var filePath = Path.Combine(dir.Path, "video.mp3");

// Act
await youtube
.Videos
.DownloadAsync(
"9bZkp7q19f0",
filePath,
o =>
o.SetFFmpegPath(FFmpeg.FilePath)
.SetContainer("mp4")
.SetPreset(ConversionPreset.UltraFast)
);
await youtube.Videos.DownloadAsync(
"9bZkp7q19f0",
filePath,
o =>
o.SetFFmpegPath(FFmpeg.FilePath)
.SetContainer("mp4")
.SetPreset(ConversionPreset.UltraFast)
);

// Assert
MediaFormat.IsMp4File(filePath).Should().BeTrue();
}

[Fact]
public async Task I_can_try_to_download_a_video_and_get_an_error_if_the_conversion_settings_are_invalid()
{
// Arrange
var youtube = new YoutubeClient();

using var dir = TempDir.Create();
var filePath = Path.Combine(dir.Path, "video.mp4");

// Act & assert
var ex = await Assert.ThrowsAnyAsync<Exception>(
async () =>
await youtube.Videos.DownloadAsync(
"9bZkp7q19f0",
filePath,
o =>
o.SetFFmpegPath(FFmpeg.FilePath)
.SetContainer("invalid_format")
.SetPreset(ConversionPreset.UltraFast)
)
);

Directory.EnumerateFiles(dir.Path, "*", SearchOption.AllDirectories).Should().BeEmpty();

testOutput.WriteLine(ex.ToString());
}

[Fact]
public async Task I_can_download_a_video_while_tracking_progress()
{
Expand All @@ -224,6 +241,6 @@ public async Task I_can_download_a_video_while_tracking_progress()
progressValues.Should().NotContain(p => p < 0 || p > 1);

foreach (var value in progressValues)
_testOutput.WriteLine($"Progress: {value:P2}");
testOutput.WriteLine($"Progress: {value:P2}");
}
}
24 changes: 14 additions & 10 deletions YoutubeDownloader.Converter.Tests/SubtitleSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,23 @@ public async Task I_can_download_a_video_as_a_single_mp4_file_with_subtitles()
using var dir = TempDir.Create();
var filePath = Path.Combine(dir.Path, "video.mp4");

var streamManifest = await youtube.Videos.Streams.GetManifestAsync("YltHGKX80Y8");
var streamManifest = await youtube.Videos.Streams.GetManifestAsync("NtQkz0aRDe8");
var streamInfos = streamManifest
.GetVideoStreams()
.Where(s => s.Container == Container.Mp4)
.OrderBy(s => s.Size)
.Take(1)
.ToArray();

var trackManifest = await youtube.Videos.ClosedCaptions.GetManifestAsync("YltHGKX80Y8");
var trackManifest = await youtube.Videos.ClosedCaptions.GetManifestAsync("NtQkz0aRDe8");
var trackInfos = trackManifest.Tracks;

// Act
await youtube
.Videos
.DownloadAsync(streamInfos, trackInfos, new ConversionRequestBuilder(filePath).Build());
await youtube.Videos.DownloadAsync(
streamInfos,
trackInfos,
new ConversionRequestBuilder(filePath).Build()
);

// Assert
MediaFormat.IsMp4File(filePath).Should().BeTrue();
Expand All @@ -61,21 +63,23 @@ public async Task I_can_download_a_video_as_a_single_webm_file_with_subtitles()
using var dir = TempDir.Create();
var filePath = Path.Combine(dir.Path, "video.webm");

var streamManifest = await youtube.Videos.Streams.GetManifestAsync("YltHGKX80Y8");
var streamManifest = await youtube.Videos.Streams.GetManifestAsync("NtQkz0aRDe8");
var streamInfos = streamManifest
.GetVideoStreams()
.Where(s => s.Container == Container.WebM)
.OrderBy(s => s.Size)
.Take(1)
.ToArray();

var trackManifest = await youtube.Videos.ClosedCaptions.GetManifestAsync("YltHGKX80Y8");
var trackManifest = await youtube.Videos.ClosedCaptions.GetManifestAsync("NtQkz0aRDe8");
var trackInfos = trackManifest.Tracks;

// Act
await youtube
.Videos
.DownloadAsync(streamInfos, trackInfos, new ConversionRequestBuilder(filePath).Build());
await youtube.Videos.DownloadAsync(
streamInfos,
trackInfos,
new ConversionRequestBuilder(filePath).Build()
);

// Assert
MediaFormat.IsWebMFile(filePath).Should().BeTrue();
Expand Down
14 changes: 7 additions & 7 deletions YoutubeDownloader.Converter.Tests/Utils/FFmpeg.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static class FFmpeg
{
private static readonly SemaphoreSlim Lock = new(1, 1);

public static Version Version { get; } = new(6, 0);
public static Version Version { get; } = new(6, 1);

private static string FileName { get; } =
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "ffmpeg.exe" : "ffmpeg";
Expand Down Expand Up @@ -71,28 +71,28 @@ static string GetHashString()
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
return "29289b1008a8fadbb012e7dc0e325fea9eebbe87ac2019a4fa7df7fc15af02d0";
return "48130a80aebffb61d06913350c3ad3187efd85096f898045fd65001bf89d7d7f";

if (RuntimeInformation.ProcessArchitecture == Architecture.X86)
return "edc8c9bda8a10e138386cd9b6953127906bde0f89d2b872cf8e9046d3c559b28";
return "71e83e4d5b4ed8e9e5b13a8bc118b73affef2ff12f9e14c388bfb17db7008f8d";

if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
return "dfd42f47c47559ccb594965f897530bb9daa62d4ce6883c3f4082b7d037832d1";
return "cd2d765565d1cc36e3fc0653d8ad6444c1736b883144de885c1f178a404c977c";
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
return "0b7808c8f93a3235efc2448c33086e8ce10295999bd93a40b060fbe7f2e92338";
return "856b4f0e5cd9de45c98b703f7258d578bbdc0ac818073a645315241f9e7d5780";
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
return "7898153f5785a739b1314ef3fb9c511be26bc7879d972c301a170e6ab8027652";
return "1671abe5dcc0b4adfaea6f2e531e377a3ccd8ea21aa2b5a0589b0e5ae7d85a37";

if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
return "a26adea0b56376df8c46118c15ae478ba02e9ac57097f569a32100760cea1cd2";
return "bcbc7de089f68c3565dd40e8fe462df28a181af8df756621fc4004a747b845cf";
}

throw new NotSupportedException("Unsupported architecture.");
Expand Down
6 changes: 2 additions & 4 deletions YoutubeDownloader.Converter.Tests/Utils/TempDir.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@

namespace YoutubeExplode.Converter.Tests.Utils;

internal partial class TempDir : IDisposable
internal partial class TempDir(string path) : IDisposable
{
public string Path { get; }

public TempDir(string path) => Path = path;
public string Path { get; } = path;

public void Dispose()
{
Expand Down
6 changes: 2 additions & 4 deletions YoutubeDownloader.Converter.Tests/Utils/TempFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@

namespace YoutubeExplode.Converter.Tests.Utils;

internal partial class TempFile : IDisposable
internal partial class TempFile(string path) : IDisposable
{
public string Path { get; }

public TempFile(string path) => Path = path;
public string Path { get; } = path;

public void Dispose()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
Expand All @@ -10,13 +10,13 @@

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" PrivateAssets="all" />
<PackageReference Include="CSharpier.MsBuild" Version="0.26.0" PrivateAssets="all" />
<PackageReference Include="CSharpier.MsBuild" Version="0.26.7" PrivateAssets="all" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.3" PrivateAssets="all" />
<PackageReference Include="Gress" Version="2.1.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<PackageReference Include="xunit" Version="2.6.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" PrivateAssets="all" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.6.4" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading

0 comments on commit 2c13f67

Please sign in to comment.