Skip to content

Commit 5c66281

Browse files
committed
Clean up
1 parent 8e5b540 commit 5c66281

File tree

5 files changed

+202
-192
lines changed

5 files changed

+202
-192
lines changed

YoutubeExplode.Converter/ConversionExtensions.cs

Lines changed: 137 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -17,157 +17,163 @@ namespace YoutubeExplode.Converter;
1717
/// </summary>
1818
public static class ConversionExtensions
1919
{
20-
/// <summary>
21-
/// Checks whether the container is a known audio-only container.
22-
/// </summary>
23-
[Obsolete("Use the Container.IsAudioOnly property instead."), ExcludeFromCodeCoverage]
24-
public static bool IsAudioOnly(this Container container) => container.IsAudioOnly;
25-
26-
private static async IAsyncEnumerable<IStreamInfo> GetOptimalStreamInfosAsync(
27-
this VideoClient videoClient,
28-
VideoId videoId,
29-
Container container,
30-
[EnumeratorCancellation] CancellationToken cancellationToken = default
31-
)
20+
/// <inheritdoc cref="ConversionExtensions" />
21+
extension(Container container)
3222
{
33-
var streamManifest = await videoClient.Streams.GetManifestAsync(videoId, cancellationToken);
23+
/// <summary>
24+
/// Checks whether the container is a known audio-only container.
25+
/// </summary>
26+
[Obsolete("Use the Container.IsAudioOnly property instead."), ExcludeFromCodeCoverage]
27+
public bool IsAudioOnly() => container.IsAudioOnly;
28+
}
3429

35-
if (
36-
streamManifest.GetAudioOnlyStreams().Any() && streamManifest.GetVideoOnlyStreams().Any()
30+
/// <inheritdoc cref="ConversionExtensions" />
31+
extension(VideoClient videoClient)
32+
{
33+
private async IAsyncEnumerable<IStreamInfo> GetOptimalStreamInfosAsync(
34+
VideoId videoId,
35+
Container container,
36+
[EnumeratorCancellation] CancellationToken cancellationToken = default
3737
)
3838
{
39-
// Include audio stream
40-
// Priority: transcoding -> bitrate
41-
yield return streamManifest
42-
.GetAudioOnlyStreams()
43-
.OrderByDescending(s => s.Container == container)
44-
.ThenByDescending(s => s.Bitrate)
45-
.First();
39+
var streamManifest = await videoClient.Streams.GetManifestAsync(
40+
videoId,
41+
cancellationToken
42+
);
43+
44+
if (
45+
streamManifest.GetAudioOnlyStreams().Any()
46+
&& streamManifest.GetVideoOnlyStreams().Any()
47+
)
48+
{
49+
// Include audio stream
50+
// Priority: transcoding -> bitrate
51+
yield return streamManifest
52+
.GetAudioOnlyStreams()
53+
.OrderByDescending(s => s.Container == container)
54+
.ThenByDescending(s => s.Bitrate)
55+
.First();
4656

47-
// Include video stream
48-
if (!container.IsAudioOnly)
57+
// Include video stream
58+
if (!container.IsAudioOnly)
59+
{
60+
// Priority: video quality -> transcoding
61+
yield return streamManifest
62+
.GetVideoOnlyStreams()
63+
.OrderByDescending(s => s.VideoQuality)
64+
.ThenByDescending(s => s.Container == container)
65+
.First();
66+
}
67+
}
68+
// Use single muxed stream if adaptive streams are not available
69+
else
4970
{
5071
// Priority: video quality -> transcoding
5172
yield return streamManifest
52-
.GetVideoOnlyStreams()
73+
.GetMuxedStreams()
5374
.OrderByDescending(s => s.VideoQuality)
5475
.ThenByDescending(s => s.Container == container)
5576
.First();
5677
}
5778
}
58-
// Use single muxed stream if adaptive streams are not available
59-
else
79+
80+
/// <summary>
81+
/// Downloads the specified media streams and closed captions and processes them into a single file.
82+
/// </summary>
83+
public async ValueTask DownloadAsync(
84+
IReadOnlyList<IStreamInfo> streamInfos,
85+
IReadOnlyList<ClosedCaptionTrackInfo> closedCaptionTrackInfos,
86+
ConversionRequest request,
87+
IProgress<double>? progress = null,
88+
CancellationToken cancellationToken = default
89+
)
6090
{
61-
// Priority: video quality -> transcoding
62-
yield return streamManifest
63-
.GetMuxedStreams()
64-
.OrderByDescending(s => s.VideoQuality)
65-
.ThenByDescending(s => s.Container == container)
66-
.First();
91+
var ffmpeg = new FFmpeg(request.FFmpegCliFilePath, request.EnvironmentVariables);
92+
var converter = new Converter(videoClient, ffmpeg, request.Preset);
93+
94+
await converter.ProcessAsync(
95+
request.OutputFilePath,
96+
request.Container,
97+
streamInfos,
98+
closedCaptionTrackInfos,
99+
progress,
100+
cancellationToken
101+
);
67102
}
68-
}
69103

70-
/// <summary>
71-
/// Downloads the specified media streams and closed captions and processes them into a single file.
72-
/// </summary>
73-
public static async ValueTask DownloadAsync(
74-
this VideoClient videoClient,
75-
IReadOnlyList<IStreamInfo> streamInfos,
76-
IReadOnlyList<ClosedCaptionTrackInfo> closedCaptionTrackInfos,
77-
ConversionRequest request,
78-
IProgress<double>? progress = null,
79-
CancellationToken cancellationToken = default
80-
)
81-
{
82-
var ffmpeg = new FFmpeg(request.FFmpegCliFilePath, request.EnvironmentVariables);
83-
var converter = new Converter(videoClient, ffmpeg, request.Preset);
104+
/// <summary>
105+
/// Downloads the specified media streams and processes them into a single file.
106+
/// </summary>
107+
public async ValueTask DownloadAsync(
108+
IReadOnlyList<IStreamInfo> streamInfos,
109+
ConversionRequest request,
110+
IProgress<double>? progress = null,
111+
CancellationToken cancellationToken = default
112+
) => await videoClient.DownloadAsync(streamInfos, [], request, progress, cancellationToken);
84113

85-
await converter.ProcessAsync(
86-
request.OutputFilePath,
87-
request.Container,
88-
streamInfos,
89-
closedCaptionTrackInfos,
90-
progress,
91-
cancellationToken
92-
);
93-
}
114+
/// <summary>
115+
/// Resolves the most optimal media streams for the specified video, downloads them,
116+
/// and processes into a single file.
117+
/// </summary>
118+
public async ValueTask DownloadAsync(
119+
VideoId videoId,
120+
ConversionRequest request,
121+
IProgress<double>? progress = null,
122+
CancellationToken cancellationToken = default
123+
) =>
124+
await videoClient.DownloadAsync(
125+
await videoClient.GetOptimalStreamInfosAsync(
126+
videoId,
127+
request.Container,
128+
cancellationToken
129+
),
130+
request,
131+
progress,
132+
cancellationToken
133+
);
134+
135+
/// <summary>
136+
/// Resolves the most optimal media streams for the specified video, downloads them,
137+
/// and processes into a single file.
138+
/// </summary>
139+
/// <remarks>
140+
/// Output container is inferred from the file extension, unless explicitly specified.
141+
/// </remarks>
142+
public async ValueTask DownloadAsync(
143+
VideoId videoId,
144+
string outputFilePath,
145+
Action<ConversionRequestBuilder> configure,
146+
IProgress<double>? progress = null,
147+
CancellationToken cancellationToken = default
148+
)
149+
{
150+
var requestBuilder = new ConversionRequestBuilder(outputFilePath);
151+
configure(requestBuilder);
152+
var request = requestBuilder.Build();
94153

95-
/// <summary>
96-
/// Downloads the specified media streams and processes them into a single file.
97-
/// </summary>
98-
public static async ValueTask DownloadAsync(
99-
this VideoClient videoClient,
100-
IReadOnlyList<IStreamInfo> streamInfos,
101-
ConversionRequest request,
102-
IProgress<double>? progress = null,
103-
CancellationToken cancellationToken = default
104-
) => await videoClient.DownloadAsync(streamInfos, [], request, progress, cancellationToken);
154+
await videoClient.DownloadAsync(videoId, request, progress, cancellationToken);
155+
}
105156

106-
/// <summary>
107-
/// Resolves the most optimal media streams for the specified video, downloads them,
108-
/// and processes into a single file.
109-
/// </summary>
110-
public static async ValueTask DownloadAsync(
111-
this VideoClient videoClient,
112-
VideoId videoId,
113-
ConversionRequest request,
114-
IProgress<double>? progress = null,
115-
CancellationToken cancellationToken = default
116-
) =>
117-
await videoClient.DownloadAsync(
118-
await videoClient.GetOptimalStreamInfosAsync(
157+
/// <summary>
158+
/// Resolves the most optimal media streams for the specified video,
159+
/// downloads them, and processes into a single file.
160+
/// </summary>
161+
/// <remarks>
162+
/// Output container is inferred from the file extension.
163+
/// If none is specified, mp4 is chosen by default.
164+
/// </remarks>
165+
public async ValueTask DownloadAsync(
166+
VideoId videoId,
167+
string outputFilePath,
168+
IProgress<double>? progress = null,
169+
CancellationToken cancellationToken = default
170+
) =>
171+
await videoClient.DownloadAsync(
119172
videoId,
120-
request.Container,
173+
outputFilePath,
174+
_ => { },
175+
progress,
121176
cancellationToken
122-
),
123-
request,
124-
progress,
125-
cancellationToken
126-
);
127-
128-
/// <summary>
129-
/// Resolves the most optimal media streams for the specified video, downloads them,
130-
/// and processes into a single file.
131-
/// </summary>
132-
/// <remarks>
133-
/// Output container is inferred from the file extension, unless explicitly specified.
134-
/// </remarks>
135-
public static async ValueTask DownloadAsync(
136-
this VideoClient videoClient,
137-
VideoId videoId,
138-
string outputFilePath,
139-
Action<ConversionRequestBuilder> configure,
140-
IProgress<double>? progress = null,
141-
CancellationToken cancellationToken = default
142-
)
143-
{
144-
var requestBuilder = new ConversionRequestBuilder(outputFilePath);
145-
configure(requestBuilder);
146-
var request = requestBuilder.Build();
147-
148-
await videoClient.DownloadAsync(videoId, request, progress, cancellationToken);
177+
);
149178
}
150-
151-
/// <summary>
152-
/// Resolves the most optimal media streams for the specified video,
153-
/// downloads them, and processes into a single file.
154-
/// </summary>
155-
/// <remarks>
156-
/// Output container is inferred from the file extension.
157-
/// If none is specified, mp4 is chosen by default.
158-
/// </remarks>
159-
public static async ValueTask DownloadAsync(
160-
this VideoClient videoClient,
161-
VideoId videoId,
162-
string outputFilePath,
163-
IProgress<double>? progress = null,
164-
CancellationToken cancellationToken = default
165-
) =>
166-
await videoClient.DownloadAsync(
167-
videoId,
168-
outputFilePath,
169-
_ => { },
170-
progress,
171-
cancellationToken
172-
);
173179
}

YoutubeExplode/Common/Batch.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public static Batch<T> Create<T>(IReadOnlyList<T> items)
2323

2424
internal static class BatchExtensions
2525
{
26-
public static IAsyncEnumerable<T> FlattenAsync<T>(this IAsyncEnumerable<Batch<T>> source)
27-
where T : IBatchItem => source.SelectManyAsync(b => b.Items);
26+
extension<T>(IAsyncEnumerable<Batch<T>> source)
27+
where T : IBatchItem
28+
{
29+
public IAsyncEnumerable<T> FlattenAsync() => source.SelectManyAsync(b => b.Items);
30+
}
2831
}

YoutubeExplode/Common/IBatchItem.cs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,23 @@ public static class BatchItemExtensions
2323
// To that end, we use a marker interface and a generic constraint to limit the
2424
// set of types that these extension methods can be used on.
2525

26-
/// <summary>
27-
/// Enumerates all items in the sequence and buffers them in memory.
28-
/// </summary>
29-
public static async ValueTask<IReadOnlyList<T>> CollectAsync<T>(this IAsyncEnumerable<T> source)
30-
where T : IBatchItem => await source.ToListAsync();
26+
/// <inheritdoc cref="BatchItemExtensions" />
27+
extension<T>(IAsyncEnumerable<T> source)
28+
where T : IBatchItem
29+
{
30+
/// <summary>
31+
/// Enumerates all items in the sequence and buffers them in memory.
32+
/// </summary>
33+
public async ValueTask<IReadOnlyList<T>> CollectAsync() => await source.ToListAsync();
3134

32-
/// <summary>
33-
/// Enumerates a subset of items in the sequence and buffers them in memory.
34-
/// </summary>
35-
public static async ValueTask<IReadOnlyList<T>> CollectAsync<T>(
36-
this IAsyncEnumerable<T> source,
37-
int count
38-
)
39-
where T : IBatchItem => await source.TakeAsync(count).ToListAsync();
35+
/// <summary>
36+
/// Enumerates a subset of items in the sequence and buffers them in memory.
37+
/// </summary>
38+
public async ValueTask<IReadOnlyList<T>> CollectAsync(int count) =>
39+
await source.TakeAsync(count).ToListAsync();
4040

41-
/// <inheritdoc cref="CollectAsync{T}(System.Collections.Generic.IAsyncEnumerable{T})" />
42-
public static ValueTaskAwaiter<IReadOnlyList<T>> GetAwaiter<T>(this IAsyncEnumerable<T> source)
43-
where T : IBatchItem => source.CollectAsync().GetAwaiter();
41+
/// <inheritdoc cref="BatchItemExtensions.CollectAsync{T}(System.Collections.Generic.IAsyncEnumerable{T})" />
42+
public ValueTaskAwaiter<IReadOnlyList<T>> GetAwaiter() =>
43+
source.CollectAsync().GetAwaiter();
44+
}
4445
}

0 commit comments

Comments
 (0)