Як скачувати картинки з YouTube програмою ZennoPoster

Буває так, що необхідно скачати всі прев’ю для відео на YouTube. І приходиться згадувати як виглядає посилання на прев’ю того чи іншого розміру. Після чого тратити час на те, щоб перейти по кожному, і завантажити прев’ю в якусь папку на комп’ютері. Тому, рішив накидати проєкт, який буде виконувати цю роботу замість мене.

Логіка роботи буде приблизно такою – я, як користувач скопіюю посилання на відео з адресного рядка браузера чи натиснувши на кнопку поділитись біля відео. В цей момент посилання буде знаходитись в буфері обміну.

Після чого, я зможу клікнути по кнопці +1 в програмі ZennoPoster біля проєкту, який буде створений в цій публікації, і ZennoPoster скопіює текст з буферу обміну. Після чого витягне звідти ID відео YouTube, як я вже писав в іншій публікації. А дальше сформує всі відомі мені варіанти посилань на прев’ю до відео і завантажить їх.

Кожне прев’ю буде збережено в папці, яка буде названа по ID відео, в назві картинки буде вказано реальний розмір картинки і ім’я файла, щоб було зрозуміло по якому посиланні вона була завантажена.

Саму реалізацію я розбив на два блоки.
Першим ділом виділяю функції, які будуть в першому блоці.

var list = new List<string>();
	list.Add("0.jpg");
	list.Add("1.jpg");
	list.Add("2.jpg");
	list.Add("3.jpg");
	list.Add("hqdefault.jpg");
	list.Add("mqdefault.jpg");
	list.Add("default.jpg");
	list.Add("sddefault.jpg");
	list.Add("maxresdefault.jpg");
	list.Add("oar2.jpg");
	list.Add("hq720_2.jpg");
	list.Add("hq720.jpg");

Func<string, byte[]> Get = delegate(string url) {
    var type = ZennoLab.InterfacesLibrary.Enums.Http.ResponceType.BodyOnly;
    var method = ZennoLab.InterfacesLibrary.Enums.Http.HttpMethod.GET;
    byte[] bytes = new Byte[0];
    try {
        bytes = ZennoPoster.HTTP.RequestBytes(
            method: method, // метод яким буде відправлено запит
            url: url,// по якому адресу буде відправлено запит
            content: string.Empty,
            contentPostingType: string.Empty,
            proxy: string.Empty,
            respType: type, // в якому вигляді повернути результат
            UseOriginalUrl: true, // не змінювати параметри запиту
            removeDefaultHeaders: true // видалення стандартних заголовків
        );
    }
    catch {
        project.SendErrorToLog("error get",true);
    }
    return bytes;
};


Func<byte[], string, string, bool> Save = delegate(byte[] image, string id, string name) {
	string dir = Path.Combine(project.Directory, id);
	if(!Directory.Exists(dir)) Directory.CreateDirectory(dir);
    bool check = false;
    try {
        using (var ms = new MemoryStream(image)){
            using (var img = Image.FromStream(ms)) {
                if(img.Width > 0){    
					string file = string.Format("{0}x{1}_{2}", img.Width, img.Height, name);
                    img.Save(Path.Combine(dir, file), System.Drawing.Imaging.ImageFormat.Jpeg);
                    check = true;            
                }         
            }
        }
    }
    catch {
        project.SendInfoToLog("error save",true);
    }
    return check;
};

// Підключити в GAS System.Web.dll
Func<string, string> GetId = delegate(string url){
	string id = string.Empty;
	try {
	var uri = new Uri(url);
	string query = uri.Query;
	if(string.IsNullOrEmpty(query)) id =  Path.GetFileNameWithoutExtension(uri.AbsolutePath);
	else {
		var param = System.Web.HttpUtility.ParseQueryString(query);
		var dic = param.AllKeys.ToDictionary(key => key, key => param[key]);
		id = dic.ContainsKey("v") ? dic["v"] : Path.GetFileNameWithoutExtension(uri.AbsolutePath);
	}
	}
	catch (Exception e) {
		project.SendWarningToLog(e.Message, true);
	}
	return id;
};

project.Context["id"] = GetId;   
project.Context["name"] = list;
project.Context["sw"] = System.Diagnostics.Stopwatch.StartNew();
project.Context["get"] = Get;
project.Context["save"] = Save;

Після чого уже в іншому блоці я буду визивати функції, які описав в першому блоці.
Це дасть мені змогу у випадку необхідності обробляти не тільки одне посилання, а і список посиланнь (для цього потрібно буде внести зміни в код).

string url = System.Windows.Forms.Clipboard.GetText();
string id = project.Context["id"](url);
if(string.IsNullOrEmpty(id)) throw new Exception("id відео не знайдено");

List<string> list = (List<string>) project.Context["name"];
foreach(string name in list) {
	string url_image = string.Format("https://i.ytimg.com/vi/{0}/{1}",id,name );
	var bytes = project.Context["get"](url_image);
	bool check = project.Context["save"](bytes, id, name);
	project.SendInfoToLog(string.Format("{0} {1} {2}", id, name, check),true);
}

var sw = project.Context["sw"];
sw.Stop();
project.SendInfoToLog(string.Format("Стоп: {0:c} ms", sw.Elapsed));

Мені завжди цікаво скільки часу виконувався проєкт, тому я добавив також вимірювання часу, і виводжу його в лог тільки в Project Maker. Тепер цей проєкт я можу добавити собі в ZennoPoster і виконувати його в будь-який момент, коли в мене є необхідність зберегти прев’юшки до відео. В лог буде виведено приблизно такі повідомлення:

09:51:28	 RYbrWFWdOE0 0.jpg True
09:51:28	 RYbrWFWdOE0 1.jpg True
09:51:28	 RYbrWFWdOE0 2.jpg True
09:51:28	 RYbrWFWdOE0 3.jpg True
09:51:28	 RYbrWFWdOE0 hqdefault.jpg True
09:51:29	 RYbrWFWdOE0 mqdefault.jpg True
09:51:29	 RYbrWFWdOE0 default.jpg True
09:51:29	 RYbrWFWdOE0 sddefault.jpg True
09:51:29	 RYbrWFWdOE0 maxresdefault.jpg True
09:51:31	 RYbrWFWdOE0 oar2.jpg True
09:51:31	 RYbrWFWdOE0 hq720_2.jpg True
09:51:31	 RYbrWFWdOE0 hq720.jpg True

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *