Буває так, що необхідно скачати всі прев’ю для відео на 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