Skip to content

Commit d8b4747

Browse files
committed
feat(download): replace manual yt-dlp with YoutubeDLSharp package
closes #4
1 parent 89395f7 commit d8b4747

2 files changed

Lines changed: 68 additions & 59 deletions

File tree

TelegramBot/MediaGet.cs

Lines changed: 67 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111

1212
using System.Diagnostics;
1313
using System.Net;
14+
using YoutubeDLSharp;
15+
using YoutubeDLSharp.Options;
1416

1517
namespace TelegramMediaRelayBot
1618
{
1719
public class MediaGet
1820
{
19-
private static readonly string[] ColonSpaceSeparator = [": "];
20-
2121
public static async Task<List<byte[]>?> DownloadMedia(ITelegramBotClient botClient, string videoUrl, Message statusMessage, CancellationToken cancellationToken)
2222
{
2323
try
@@ -34,10 +34,10 @@ public class MediaGet
3434
}
3535

3636
Log.Debug("Starting video download via yt-dlp...");
37-
37+
3838
string tempDirPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
3939
Directory.CreateDirectory(tempDirPath);
40-
40+
4141
if (Config.torEnabled)
4242
{
4343
var proxy = new WebProxy($"socks5://{Config.torSocksHost}:{Config.torSocksPort}");
@@ -47,80 +47,88 @@ public class MediaGet
4747
Log.Debug("Tor IP: " + result);
4848
}
4949

50-
var startInfo = new ProcessStartInfo
50+
var ytdl = new YoutubeDL
5151
{
52-
FileName = "yt-dlp",
53-
Arguments = $"--proxy \"{Config.proxy}\" -v -f mp4 --output \"{tempDirPath}/video.%(ext)s\" {videoUrl}",
54-
RedirectStandardOutput = true,
55-
RedirectStandardError = true,
56-
UseShellExecute = false,
57-
CreateNoWindow = true
52+
YoutubeDLPath = "yt-dlp",
53+
OutputFolder = tempDirPath,
54+
OutputFileTemplate = "video.%(ext)s",
55+
OverwriteFiles = true
5856
};
5957

60-
using (Process process = new Process { StartInfo = startInfo })
58+
var overrideOptions = new OptionSet
6159
{
62-
process.Start();
63-
Log.Debug("Process started.");
64-
65-
List<string> outputLines = new List<string>();
66-
List<string> errorLines = new List<string>();
60+
Format = "mp4",
61+
Verbose = true
62+
};
6763

68-
Task readOutputTask = ReadLinesAsync(process.StandardOutput, outputLines, botClient, statusMessage, cancellationToken);
69-
Task readErrorTask = ReadLinesAsync(process.StandardError, errorLines, botClient, statusMessage, cancellationToken);
64+
if (!string.IsNullOrEmpty(Config.proxy))
65+
{
66+
overrideOptions.Proxy = Config.proxy;
67+
}
7068

71-
await process.WaitForExitAsync();
69+
DateTime lastProgressUpdate = DateTime.MinValue;
70+
var progress = new Progress<DownloadProgress>(p =>
71+
{
72+
if (DateTime.UtcNow - lastProgressUpdate < TimeSpan.FromMilliseconds(Config.videoGetDelay))
73+
return;
7274

73-
await Task.WhenAll(readOutputTask, readErrorTask);
75+
lastProgressUpdate = DateTime.UtcNow;
76+
int percent = (int)(p.Progress * 100);
77+
string statusText = $"[download] {percent}%";
78+
if (!string.IsNullOrEmpty(p.DownloadSpeed))
79+
statusText += $" at {p.DownloadSpeed}";
80+
if (!string.IsNullOrEmpty(p.ETA))
81+
statusText += $" ETA {p.ETA}";
7482

75-
string output = string.Join("\n", outputLines);
76-
string error = string.Join("\n", errorLines);
83+
if (Config.showVideoDownloadProgress)
84+
Log.Debug($"Video download progress: {statusText}");
7785

78-
if (process.ExitCode == 0)
86+
_ = Task.Run(async () =>
7987
{
8088
try
8189
{
82-
string? downloadLine = output.Split('\n').FirstOrDefault(line => line.StartsWith("[download] Destination:"));
83-
if (downloadLine == null)
84-
{
85-
Log.Error("Could not find download destination in yt-dlp output.");
86-
return null;
87-
}
88-
89-
string[] parts = downloadLine.Split(ColonSpaceSeparator, 2, StringSplitOptions.None);
90-
if (parts.Length < 2)
91-
{
92-
Log.Error("Download destination not found in yt-dlp output.");
93-
return null;
94-
}
95-
96-
string finalFilePath = parts[1].Trim();
97-
Log.Debug($"Final file path: {finalFilePath}");
98-
99-
if (System.IO.File.Exists(finalFilePath))
100-
{
101-
List<byte[]>? videoBytes = new List<byte[]> { System.IO.File.ReadAllBytes(finalFilePath) };
102-
103-
System.IO.File.Delete(finalFilePath);
104-
Directory.Delete(tempDirPath, recursive: true);
105-
106-
return videoBytes;
107-
}
108-
109-
Log.Error($"Final file does not exist: {finalFilePath}");
90+
await botClient.EditMessageText(
91+
statusMessage.Chat.Id,
92+
statusMessage.MessageId,
93+
statusText,
94+
cancellationToken: cancellationToken);
11095
}
11196
catch (Exception ex)
11297
{
113-
Log.Error(ex, $"Error reading file: {ex.Message}");
98+
Log.Debug(ex, "Error editing message.");
11499
}
115-
}
116-
else
100+
});
101+
});
102+
103+
var downloadResult = await ytdl.RunVideoDownload(
104+
videoUrl,
105+
format: "mp4",
106+
ct: cancellationToken,
107+
progress: progress,
108+
overrideOptions: overrideOptions);
109+
110+
if (downloadResult.Success)
111+
{
112+
string filePath = downloadResult.Data;
113+
Log.Debug($"Final file path: {filePath}");
114+
115+
if (System.IO.File.Exists(filePath))
117116
{
118-
Log.Error("Video download failed: " + error);
117+
byte[] videoBytes = await System.IO.File.ReadAllBytesAsync(filePath, cancellationToken);
118+
Directory.Delete(tempDirPath, recursive: true);
119+
return new List<byte[]> { videoBytes };
119120
}
120-
121-
Directory.Delete(tempDirPath, recursive: true);
122-
return null;
121+
122+
Log.Error($"Final file does not exist: {filePath}");
123+
}
124+
else
125+
{
126+
string errors = string.Join("\n", downloadResult.ErrorOutput);
127+
Log.Error("Video download failed: " + errors);
123128
}
129+
130+
Directory.Delete(tempDirPath, recursive: true);
131+
return null;
124132
}
125133
catch (Exception ex)
126134
{

TelegramMediaRelayBot.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,6 @@
4343
<None Update="yt-dlp">
4444
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
4545
</None>
46+
<PackageReference Include="YoutubeDLSharp" Version="1.2.0" />
4647
</ItemGroup>
4748
</Project>

0 commit comments

Comments
 (0)