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