From d691bef1fbdb45127f32656f28b613d808f18e68 Mon Sep 17 00:00:00 2001
From: chylex <contact@chylex.com>
Date: Sun, 27 Aug 2017 18:23:50 +0200
Subject: [PATCH] Add video context menu items and update video service check

---
 Core/Handling/ContextMenuBase.cs | 13 +++++++++++--
 Core/Utils/TwitterUtils.cs       | 31 +++++++++++++++++++++++++------
 Resources/Scripts/code.js        |  9 ++++++++-
 tests/Core/TestTwitterUtils.cs   | 20 ++++++++++----------
 4 files changed, 54 insertions(+), 19 deletions(-)

diff --git a/Core/Handling/ContextMenuBase.cs b/Core/Handling/ContextMenuBase.cs
index 9765c3e3..73d842a9 100644
--- a/Core/Handling/ContextMenuBase.cs
+++ b/Core/Handling/ContextMenuBase.cs
@@ -78,6 +78,10 @@ public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser bro
             }
 
             if (hasTweetVideo){
+                model.AddItem(MenuOpenMediaUrl, TextOpen("video"));
+                model.AddItem(MenuCopyMediaUrl, TextCopy("video"));
+                model.AddItem(MenuSaveMedia, TextSave("video"));
+                model.AddSeparator();
             }
             else if ((parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents) || hasTweetImage){
                 model.AddItem(MenuOpenMediaUrl, TextOpen("image"));
@@ -108,15 +112,20 @@ public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser br
                     break;
 
                 case MenuOpenMediaUrl:
-                    BrowserUtils.OpenExternalBrowser(TwitterUtils.GetImageLink(GetMediaLink(parameters), ImageQuality));
+                    BrowserUtils.OpenExternalBrowser(TwitterUtils.GetMediaLink(GetMediaLink(parameters), ImageQuality));
                     break;
 
                 case MenuCopyMediaUrl:
-                    SetClipboardText(TwitterUtils.GetImageLink(GetMediaLink(parameters), ImageQuality));
+                    SetClipboardText(TwitterUtils.GetMediaLink(GetMediaLink(parameters), ImageQuality));
                     break;
 
                 case MenuSaveMedia:
+                    if (IsVideo){
+                        TwitterUtils.DownloadVideo(GetMediaLink(parameters));
+                    }
+                    else{
                         TwitterUtils.DownloadImage(GetMediaLink(parameters), lastHighlightedTweetAuthor, ImageQuality);
+                    }
 
                     break;
 
diff --git a/Core/Utils/TwitterUtils.cs b/Core/Utils/TwitterUtils.cs
index f1915d62..b1aa0d76 100644
--- a/Core/Utils/TwitterUtils.cs
+++ b/Core/Utils/TwitterUtils.cs
@@ -33,14 +33,14 @@ public static bool IsTwitterWebsite(IFrame frame){
             return frame.Url.Contains("//twitter.com/");
         }
 
-        private static string ExtractImageBaseLink(string url){
+        private static string ExtractMediaBaseLink(string url){
             int dot = url.LastIndexOf('/');
             return dot == -1 ? url : StringUtils.ExtractBefore(url, ':', dot);
         }
 
-        public static string GetImageLink(string url, ImageQuality quality){
+        public static string GetMediaLink(string url, ImageQuality quality){
             if (quality == ImageQuality.Orig){
-                string result = ExtractImageBaseLink(url);
+                string result = ExtractMediaBaseLink(url);
 
                 if (result != url || url.Contains("//pbs.twimg.com/media/")){
                     result += ":orig";
@@ -62,10 +62,10 @@ public static void DownloadImages(string[] urls, string username, ImageQuality q
                 return;
             }
 
-            string firstImageLink = GetImageLink(urls[0], quality);
+            string firstImageLink = GetMediaLink(urls[0], quality);
             int qualityIndex = firstImageLink.IndexOf(':', firstImageLink.LastIndexOf('/'));
 
-            string file = BrowserUtils.GetFileNameFromUrl(ExtractImageBaseLink(firstImageLink));
+            string file = BrowserUtils.GetFileNameFromUrl(ExtractMediaBaseLink(firstImageLink));
             string ext = Path.GetExtension(file); // includes dot
 
             string[] fileNameParts = qualityIndex == -1 ? new string[]{
@@ -96,11 +96,30 @@ void OnFailure(Exception ex){
                         string pathExt = Path.GetExtension(dialog.FileName);
 
                         for(int index = 0; index < urls.Length; index++){
-                            BrowserUtils.DownloadFileAsync(GetImageLink(urls[index], quality), $"{pathBase} {index+1}{pathExt}", null, OnFailure);
+                            BrowserUtils.DownloadFileAsync(GetMediaLink(urls[index], quality), $"{pathBase} {index+1}{pathExt}", null, OnFailure);
                         }
                     }
                 }
             }
         }
+
+        public static void DownloadVideo(string url){
+            string filename = BrowserUtils.GetFileNameFromUrl(url);
+            string ext = Path.GetExtension(filename);
+
+            using(SaveFileDialog dialog = new SaveFileDialog{
+                AutoUpgradeEnabled = true,
+                OverwritePrompt = true,
+                Title = "Save video",
+                FileName = filename,
+                Filter = "Video"+(string.IsNullOrEmpty(ext) ? " (unknown)|*.*" : $" (*{ext})|*{ext}")
+            }){
+                if (dialog.ShowDialog() == DialogResult.OK){
+                    BrowserUtils.DownloadFileAsync(url, dialog.FileName, null, ex => {
+                        FormMessage.Error("Image Download", "An error occurred while downloading the image: "+ex.Message, FormMessage.OK);
+                    });
+                }
+            }
+        }
     }
 }
diff --git a/Resources/Scripts/code.js b/Resources/Scripts/code.js
index b5d2f8c8..a79a7e0c 100644
--- a/Resources/Scripts/code.js
+++ b/Resources/Scripts/code.js
@@ -381,8 +381,15 @@
     if (me.classList.contains("js-media-image-link") && highlightedTweetObj){
       let media = (highlightedTweetObj.quotedTweet || highlightedTweetObj).getMedia().find(media => media.mediaId === me.getAttribute("data-media-entity-id"));
       
+      if ((media.isVideo && media.service === "twitter") || media.isAnimatedGif){
+        $TD.setLastRightClickInfo("video", media.chooseVideoVariant().url);
+      }
+      else{
         $TD.setLastRightClickInfo("image", media.large());
+      }
     }
+    else if (me.classList.contains("js-gif-play")){
+      $TD.setLastRightClickInfo("video", $(this).closest(".js-media-gif-container").find("video").attr("src"));
     }
     else{
       $TD.setLastRightClickInfo("link", me.getAttribute("data-full-url"));
@@ -838,7 +845,7 @@
     TD.components.MediaGallery.prototype._loadTweet = appendToFunction(TD.components.MediaGallery.prototype._loadTweet, function(){
       let media = this.chirp.getMedia().find(media => media.mediaId === this.clickedMediaEntityId);
 
-      if (media && media.isVideo && media.service !== "youtube"){
+      if (media && media.isVideo && media.service === "twitter"){
         playVideo(media.chooseVideoVariant().url);
         cancelModal = true;
       }
diff --git a/tests/Core/TestTwitterUtils.cs b/tests/Core/TestTwitterUtils.cs
index dc14af70..5b4e29d0 100644
--- a/tests/Core/TestTwitterUtils.cs
+++ b/tests/Core/TestTwitterUtils.cs
@@ -26,20 +26,20 @@ public void TestAccountRegex(){
 
         [TestMethod]
         public void TestImageQualityLink(){
-            Assert.AreEqual("https://pbs.twimg.com/profile_images/123", TwitterUtils.GetImageLink("https://pbs.twimg.com/profile_images/123", TwitterUtils.ImageQuality.Default));
-            Assert.AreEqual("https://pbs.twimg.com/profile_images/123", TwitterUtils.GetImageLink("https://pbs.twimg.com/profile_images/123", TwitterUtils.ImageQuality.Orig));
+            Assert.AreEqual("https://pbs.twimg.com/profile_images/123", TwitterUtils.GetMediaLink("https://pbs.twimg.com/profile_images/123", TwitterUtils.ImageQuality.Default));
+            Assert.AreEqual("https://pbs.twimg.com/profile_images/123", TwitterUtils.GetMediaLink("https://pbs.twimg.com/profile_images/123", TwitterUtils.ImageQuality.Orig));
 
-            Assert.AreEqual("https://pbs.twimg.com/profile_images/123.jpg", TwitterUtils.GetImageLink("https://pbs.twimg.com/profile_images/123.jpg", TwitterUtils.ImageQuality.Default));
-            Assert.AreEqual("https://pbs.twimg.com/profile_images/123.jpg", TwitterUtils.GetImageLink("https://pbs.twimg.com/profile_images/123.jpg", TwitterUtils.ImageQuality.Orig));
+            Assert.AreEqual("https://pbs.twimg.com/profile_images/123.jpg", TwitterUtils.GetMediaLink("https://pbs.twimg.com/profile_images/123.jpg", TwitterUtils.ImageQuality.Default));
+            Assert.AreEqual("https://pbs.twimg.com/profile_images/123.jpg", TwitterUtils.GetMediaLink("https://pbs.twimg.com/profile_images/123.jpg", TwitterUtils.ImageQuality.Orig));
 
-            Assert.AreEqual("https://pbs.twimg.com/media/123.jpg", TwitterUtils.GetImageLink("https://pbs.twimg.com/media/123.jpg", TwitterUtils.ImageQuality.Default));
-            Assert.AreEqual("https://pbs.twimg.com/media/123.jpg:orig", TwitterUtils.GetImageLink("https://pbs.twimg.com/media/123.jpg", TwitterUtils.ImageQuality.Orig));
+            Assert.AreEqual("https://pbs.twimg.com/media/123.jpg", TwitterUtils.GetMediaLink("https://pbs.twimg.com/media/123.jpg", TwitterUtils.ImageQuality.Default));
+            Assert.AreEqual("https://pbs.twimg.com/media/123.jpg:orig", TwitterUtils.GetMediaLink("https://pbs.twimg.com/media/123.jpg", TwitterUtils.ImageQuality.Orig));
 
-            Assert.AreEqual("https://pbs.twimg.com/media/123.jpg:small", TwitterUtils.GetImageLink("https://pbs.twimg.com/media/123.jpg:small", TwitterUtils.ImageQuality.Default));
-            Assert.AreEqual("https://pbs.twimg.com/media/123.jpg:orig", TwitterUtils.GetImageLink("https://pbs.twimg.com/media/123.jpg:small", TwitterUtils.ImageQuality.Orig));
+            Assert.AreEqual("https://pbs.twimg.com/media/123.jpg:small", TwitterUtils.GetMediaLink("https://pbs.twimg.com/media/123.jpg:small", TwitterUtils.ImageQuality.Default));
+            Assert.AreEqual("https://pbs.twimg.com/media/123.jpg:orig", TwitterUtils.GetMediaLink("https://pbs.twimg.com/media/123.jpg:small", TwitterUtils.ImageQuality.Orig));
 
-            Assert.AreEqual("https://pbs.twimg.com/media/123.jpg:large", TwitterUtils.GetImageLink("https://pbs.twimg.com/media/123.jpg:large", TwitterUtils.ImageQuality.Default));
-            Assert.AreEqual("https://pbs.twimg.com/media/123.jpg:orig", TwitterUtils.GetImageLink("https://pbs.twimg.com/media/123.jpg:large", TwitterUtils.ImageQuality.Orig));
+            Assert.AreEqual("https://pbs.twimg.com/media/123.jpg:large", TwitterUtils.GetMediaLink("https://pbs.twimg.com/media/123.jpg:large", TwitterUtils.ImageQuality.Default));
+            Assert.AreEqual("https://pbs.twimg.com/media/123.jpg:orig", TwitterUtils.GetMediaLink("https://pbs.twimg.com/media/123.jpg:large", TwitterUtils.ImageQuality.Orig));
         }
     }
 }