Python Download Youtube Playlist (C# UI & Parallel Programming)
- Edward Low

- 2020年1月3日
- 讀畢需時 2 分鐘
In this project, I am trying to show how to download youtube playlists in a concurrent or simultaneous way or we called it embarrassingly parallel.
The purpose of this project is to ease myself for downloading youtube video. This is because I found out some of the online youtube downloader, there are limited attempts for user download any playlist they want and some of the tools that are required user to create a folder and rename them for saving the video. Those are very troublesome works. The better tool i have been used last time, called youtube playlist downloader, but it only provide free 30 days trial, it need a few hundred for subscription.
Therefore, I am planning to create a simple tool to download all the videos by passing the target url of the youtube playlist.
Each of the downloading speed have been limited, only can reach MTU, therefore, I used parallel programming to download four playlist at the same time to fully utilized the network speed.
Before starting of this program, we need to download youtube-dl module in the python.
Command: Pip install youtube-dl
After done installation, we start to write the C# to create GUI and interoperate with Python script. The reason that I used C# is because it can create better GUI comparing with Python Tkinder.

After we click the run button, it will call the python script and download the video one by one.

There are the folder created during the downloading process.
Source Code for C#:
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Diagnostics;
using System.Threading;
using System.IO;
using System.Collections;
namespace YoutubeDownloader
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public ArrayList array = new ArrayList();
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
File.WriteAllText("urls.txt", StringFromRichTextBox(urlTextBox));
Thread[] tarray = new Thread[4];
foreach (string file in File.ReadAllLines("urls.txt"))
{
array.Add(file);
}
for (int i = 0; i < tarray.Length; i++)
{
ParameterizedThreadStart start = new ParameterizedThreadStart(Optional_ExecProcess);
tarray[i] = new Thread(start);
tarray[i].Start(i);
}
for (int i = 0; i < tarray.Length; i++)
{
tarray[i].Join();
}
}
private void Optional_ExecProcess(Object tid)
{
int id = (int)tid;
// Create Process Info
for (int p = id; p < array.Count; p += 4)
{
var psi = new ProcessStartInfo();
psi.FileName = @"D:\Program Files (x86)\Python3.6.8\python.exe";
// Provide Script and arguments
var script = @"C:\Users\jinzh\PycharmProjects\YoutubeDownloader\main\YoutubeDownloader\Downloader.py";
psi.Arguments = $"\"{script}\" \"{array[p]}\"";
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
var errors = "";
var results = "";
using (var process = Process.Start(psi))
{
errors = process.StandardError.ReadToEnd();
results = process.StandardOutput.ReadToEnd();
}
Console.WriteLine("Errors");
Console.WriteLine(errors);
Console.WriteLine("Results");
Console.WriteLine(results);
}
}
private string StringFromRichTextBox(RichTextBox rtb)
{
TextRange textRange = new TextRange(
// TextPointer to the start of content in the RichTextBox.
rtb.Document.ContentStart,
// TextPointer to the end of content in the RichTextBox.
rtb.Document.ContentEnd
);
// The Text property on a TextRange object returns a string
// representing the plain text content of the TextRange.
return textRange.Text;
}
}
}
Source Code for Python:
import youtube_dl
import os
import sys
import time
videoDir = os.path.join(os.path.dirname(os.getcwd()), "Video")
class downloader:
def ydl_download(self, playlist):
print(videoDir)
ydl_opts = {
'ignoreerrors' : True,
'quiet' : True
}
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
playlist_dict = ydl.extract_info(playlist, download=False)
self.file_validator(playlist_dict.get('title'))
ydl.extract_info(playlist, download=True)
def file_validator(self, playlist_title):
path = os.path.join(videoDir, playlist_title)
if not os.path.exists(path):
os.mkdir(path)
os.chdir(path)
if __name__ == '__main__':
url = sys.argv[1]
ydl = downloader().ydl_download(url)

留言