Skip to content

Instantly share code, notes, and snippets.

@JKamsker
Created December 22, 2016 21:46
Show Gist options
  • Save JKamsker/fae79a2ba8b2fb06e957bc618671376e to your computer and use it in GitHub Desktop.
Save JKamsker/fae79a2ba8b2fb06e957bc618671376e to your computer and use it in GitHub Desktop.
Async youtube-dl wrapper
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace MediaProviderWorker.Helpers.Youtube
{
class usage
{
public static void use(string[] args)
{
var dat = new YoutubeProvider(args.Length != 0 ? args[0] : "https://www.youtube.com/watch?v=IxuEtL7gxoM");
var dat1 = new YoutubeProvider(args.Length > 1 ? args[1] : "https://www.youtube.com/watch?v=VmUGe8KDdGI");
while (!dat.hasFinished || !dat1.hasFinished)
{
WaitHandle.WaitAny(new[] { dat.waiter, dat1.waiter }, -1);
// dat.WaitOne(); for one or "WaitHandle.WaitAny(new[] { dat.waiter, dat1.waiter }, -1);" for multible downloads
Console.WriteLine("1: {0}%, {1} secs remaining", dat.percentage.ToString("0.0"), dat.eta.TotalSeconds);
Console.WriteLine("2: {0}%, {1} secs remaining", dat1.percentage.ToString("0.0"), dat1.eta.TotalSeconds);
}
File.WriteAllText(dat.saveto + ".log", dat.rawResponse);
Console.WriteLine("Finished");
Console.ReadLine();
}
}
class YoutubeProvider
{
public float percentage { get; set; }
public string size { get; set; } = string.Empty;
public string speed { get; set; } = string.Empty;
public TimeSpan eta { get; set; }
public string rawResponse { get; set; } = string.Empty;
public bool hasFinished { get; private set; }
public string saveto { get; private set; } = string.Empty;
public AutoResetEvent waiter { get { return _waiter; } private set { _waiter = value; } }
Thread _workThread;
AutoResetEvent _waiter;
private static Random random = new Random();
static readonly Regex rgxPercentage = new Regex(@"(\d+\.\d+|\d+)%", RegexOptions.Compiled | RegexOptions.ECMAScript);
static readonly Regex rgxSize = new Regex(@"of ((\d+\.\d+|\d+).*?) at", RegexOptions.Compiled | RegexOptions.ECMAScript);
static readonly Regex rgxSpeed = new Regex(@"at[ ]+((\d+\.\d+|\d+).*?\/s)", RegexOptions.Compiled | RegexOptions.ECMAScript);
static readonly Regex rgxETA = new Regex(@"ETA[ ]+((\d+\:\d+))", RegexOptions.Compiled | RegexOptions.ECMAScript);
private static string RandomString(int length) { return new string(Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", length).Select(s => s[random.Next(s.Length)]).ToArray()); }
public YoutubeProvider(string uri)
{
eta = TimeSpan.FromSeconds(0);
_waiter = new AutoResetEvent(false);
hasFinished = false;
_workThread = new Thread(() =>
{
try
{
string tmp = dlVid(uri);
lock (rawResponse) { rawResponse = tmp; }
}
catch (Exception ex)
{ Console.WriteLine(ex.Message); }
hasFinished = true;
_waiter.Set();
});
_workThread.Start();
}
public void WaitOne()
{
_waiter.WaitOne();
}
void parseDat(string input)
{
try { percentage = Convert.ToSingle(rgxPercentage.Match(input).Groups[1].Value); } catch { }
lock (size) { try { size = rgxSize.Match(input).Groups[1].Value.Replace(".", ","); } catch { } }
lock (speed) { try { speed = rgxSpeed.Match(input).Groups[1].Value; } catch { } }
try { eta = TimeSpan.ParseExact(rgxETA.Match(input).Groups[1].Value, @"mm\:ss", CultureInfo.InvariantCulture); } catch { }
if (_waiter != null)
_waiter.Set();
}
private string dlVid(string uri)
{
List<string> outPutLog = new List<string>();
lock (saveto)
{
while (true)
{
saveto = RandomString(10);
if (!File.Exists(saveto + ".mp4") &&
!File.Exists(saveto + ".mp3") &&
!File.Exists(saveto + ".webm"))
{
break;
}
Thread.SpinWait(5);
}
}
string strCommand = string.Format(Settings.ytDLarguments, saveto, uri);
DataReceivedEventHandler strHand = new DataReceivedEventHandler((sender, e) =>
{
string strMessage = e.Data;
if (strMessage != null && strMessage.Length > 0)
{
outPutLog.Add(strMessage);
parseDat(strMessage);
}
});
Process processFfmpeg = new Process()
{
EnableRaisingEvents = true,
StartInfo = new ProcessStartInfo()
{
Arguments = strCommand,
FileName = Settings.youtubeDLPath,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
}
};
processFfmpeg.ErrorDataReceived += strHand;
processFfmpeg.OutputDataReceived += strHand;
processFfmpeg.Start();
processFfmpeg.BeginOutputReadLine();
processFfmpeg.BeginErrorReadLine();
processFfmpeg.WaitForExit();
return string.Join("\n", outPutLog);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment