Open Tweet Image

A thrown together script to open a tweets image in a new tab.

  1. // ==UserScript==
  2. // @name Open Tweet Image
  3. // @author Arctosmous
  4. // @namespace https://www.googledrive.com/host/0B0T32ON-a3StUWZGUW9TbFZCVHM/
  5. // @description A thrown together script to open a tweets image in a new tab.
  6. // @include https://twitter.com/*
  7. // @exclude https://twitter.com/settings/*
  8. // @grant none
  9. // @version 1.1.0
  10. // @noframes
  11. // ==/UserScript==
  12. var OpenTweetImage;
  13. (function (OpenTweetImage) {
  14. function GetOrigUrl(url) {
  15. if (url.indexOf(":") != url.lastIndexOf(":")) {
  16. url = url.substr(0, url.lastIndexOf(':'));
  17. }
  18. return url + ':orig';
  19. }
  20. var Gallery;
  21. (function (Gallery) {
  22. var lightbox = document.getElementsByClassName("Gallery-content")[0];
  23. var imageConainer = lightbox.getElementsByClassName("Gallery-media")[0];
  24. var openLink = document.createElement("a");
  25. openLink.id = "oti-link";
  26. openLink.target = "_blank";
  27. openLink.className = "modal-btn";
  28. openLink.style.position = "absolute";
  29. openLink.style.right = "-31px";
  30. openLink.style.padding = "0";
  31. openLink.style.height = "auto";
  32. openLink.style.top = "43px";
  33. openLink.style.color = "#fff";
  34. openLink.style.fontSize = "20px";
  35. lightbox.insertBefore(openLink, lightbox.childNodes[0]);
  36. var linkIcon = document.createElement("span");
  37. linkIcon.className = "Icon Icon--photo";
  38. openLink.appendChild(linkIcon);
  39. var observer = new MutationObserver(function (mutations) {
  40. mutations.forEach(function (mutation) {
  41. if (mutation.type == "childList") {
  42. if (imageConainer.children.length !== 0) {
  43. var image = imageConainer.children[0];
  44. openLink.href = GetOrigUrl(image.src);
  45. }
  46. else {
  47. openLink.href = "";
  48. }
  49. }
  50. });
  51. });
  52. observer.observe(imageConainer, {
  53. childList: true
  54. });
  55. })(Gallery || (Gallery = {}));
  56. var TweetTools = (function () {
  57. function TweetTools(tweet) {
  58. this.openButton = document.createElement("a");
  59. var t = this;
  60. t.tweet = tweet;
  61. t.GetMedia();
  62. t.actionFooter = tweet.getElementsByClassName("ProfileTweet-actionList")[0];
  63. // First and last buttons are too wide
  64. var twitterActions = t.actionFooter.getElementsByClassName("ProfileTweet-action");
  65. var replyTwitterAction = twitterActions[0];
  66. var moreTwitterAction = twitterActions[twitterActions.length - 1];
  67. replyTwitterAction.style.width = "60px";
  68. moreTwitterAction.style.width = "50px";
  69. var openContainer = document.createElement("div");
  70. openContainer.className = "ProfileTweet-action oti-new_tabs";
  71. openContainer.appendChild(t.openButton);
  72. openContainer.style.width = "50px";
  73. t.actionFooter.appendChild(openContainer);
  74. t.openButton.className = "ProfileTweet-actionButton u-textUserColorHover js-actionButton js-tooltip";
  75. t.openButton.title = "Open All";
  76. if (t.downloadableMedia.length == 1) {
  77. t.openButton.href = t.downloadableMedia[0];
  78. t.openButton.target = "_blank";
  79. }
  80. else {
  81. t.openButton.onclick = function () {
  82. t.downloadableMedia.forEach(function (mediaUrl) {
  83. window.open(mediaUrl, "_blank");
  84. });
  85. t.mobileMedia.forEach(function (mediaUrl) {
  86. window.open(mediaUrl, "_blank");
  87. });
  88. };
  89. }
  90. var openIcon = document.createElement("span");
  91. openIcon.className = "Icon Icon--collections";
  92. t.openButton.appendChild(openIcon);
  93. tweet.className += " has-oti-tools";
  94. }
  95. TweetTools.prototype.GetMp4Gif = function (media) {
  96. var t = this;
  97. var iframe = media.getElementsByTagName("iframe")[0];
  98. var fuckingIframesPosDoesntWorkAndYourBullshit = setInterval(function () {
  99. if (iframe.contentWindow != null) {
  100. var video = iframe.contentWindow.document.getElementsByTagName("video");
  101. if (video.length > 0) {
  102. t.downloadableMedia.push(video[0].src);
  103. clearInterval(fuckingIframesPosDoesntWorkAndYourBullshit);
  104. }
  105. }
  106. else {
  107. clearInterval(fuckingIframesPosDoesntWorkAndYourBullshit);
  108. }
  109. }, 500);
  110. };
  111. TweetTools.prototype.GetMedia = function () {
  112. var t = this;
  113. var media = t.tweet.getElementsByClassName("AdaptiveMedia")[0];
  114. t.downloadableMedia = [];
  115. t.mobileMedia = [];
  116. var images = media.getElementsByTagName("img");
  117. [].forEach.call(images, function (image) {
  118. var origImg = GetOrigUrl(image.src);
  119. t.downloadableMedia.push(origImg);
  120. });
  121. if (media.classList.contains("is-generic-video")) {
  122. if (media.getElementsByClassName("PlayableMedia--gif").length > 0) {
  123. if (media.getElementsByTagName("iframe").length > 0) {
  124. t.GetMp4Gif(media);
  125. }
  126. else {
  127. var playerContainer_1 = media.getElementsByClassName("PlayableMedia-player")[0];
  128. var mediaObserver_1 = new MutationObserver(function (mutations) {
  129. mutations.forEach(function (mutation) {
  130. if (mutation.type == "childList" && playerContainer_1.children.length) {
  131. t.GetMp4Gif(media);
  132. mediaObserver_1.disconnect();
  133. }
  134. });
  135. });
  136. mediaObserver_1.observe(playerContainer_1, {
  137. childList: true
  138. });
  139. }
  140. }
  141. else {
  142. t.mobileMedia.push("https://mobile.twitter.com" + t.tweet.dataset["permalinkPath"]);
  143. }
  144. }
  145. };
  146. return TweetTools;
  147. }());
  148. function initTools() {
  149. var tweets = document.querySelectorAll(".has-cards:not(.has-oti-tools):not(.cards-forward):not([data-card2-type])");
  150. [].forEach.call(tweets, function (tweet) {
  151. new TweetTools(tweet);
  152. });
  153. }
  154. var timelineObserver = new MutationObserver(function (mutations) {
  155. mutations.forEach(function (mutation) {
  156. if (mutation.type == "childList") {
  157. initTools();
  158. }
  159. });
  160. });
  161. var overlayObserver = new MutationObserver(function (mutations) {
  162. mutations.forEach(function (mutation) {
  163. if (mutation.type == "childList") {
  164. var overlayContainer = document.getElementsByClassName("PermalinkOverlay-body")[0];
  165. if (overlayContainer.children.length !== 0) {
  166. timelineObserver.disconnect();
  167. initTools();
  168. var overlayStreams = overlayContainer.getElementsByClassName(".stream-items");
  169. [].forEach.call(overlayStreams, function (stream) {
  170. timelineObserver.observe(stream, {
  171. childList: true
  172. });
  173. });
  174. }
  175. }
  176. });
  177. });
  178. var bodyObserver = new MutationObserver(function (mutations) {
  179. mutations.forEach(function (mutation) {
  180. if (mutation.type == "attributes") {
  181. timelineObserver.disconnect();
  182. overlayObserver.disconnect();
  183. initTools();
  184. if (document.body.classList.contains("overlay-enabled")) {
  185. var overlayContainer = document.getElementsByClassName("PermalinkOverlay-body")[0];
  186. overlayObserver.observe(overlayContainer, {
  187. childList: true
  188. });
  189. [].forEach.call(overlayContainer.getElementsByClassName("stream-items"), function (stream) {
  190. timelineObserver.observe(stream, {
  191. childList: true
  192. });
  193. });
  194. }
  195. else {
  196. timelineObserver.observe(document.getElementById("stream-items-id"), {
  197. childList: true
  198. });
  199. }
  200. }
  201. });
  202. });
  203. function initBodyObserver() {
  204. bodyObserver.observe(document.body, {
  205. attributes: true
  206. });
  207. }
  208. initBodyObserver();
  209. })(OpenTweetImage || (OpenTweetImage = {}));