LinkTube

Replaces an embedded video with a link to the video page.

  1. // ==UserScript==
  2. // @name LinkTube
  3. // @version 2019.11.25
  4. // @description Replaces an embedded video with a link to the video page.
  5. // @author sebaro
  6. // @namespace http://sebaro.pro/linktube
  7. // @icon https://gitlab.com/sebaro/linktube/raw/master/linktube.png
  8. // @include *
  9. // ==/UserScript==
  10.  
  11.  
  12. /*
  13.  
  14. Copyright (C) 2011 - 2019 Sebastian Luncan
  15.  
  16. This program is free software: you can redistribute it and/or modify
  17. it under the terms of the GNU General Public License as published by
  18. the Free Software Foundation, either version 3 of the License, or
  19. (at your option) any later version.
  20.  
  21. This program is distributed in the hope that it will be useful,
  22. but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. GNU General Public License for more details.
  25.  
  26. You should have received a copy of the GNU General Public License
  27. along with this program. If not, see <http://www.gnu.org/licenses/>.
  28.  
  29. Website: http://sebaro.pro/linktube
  30. Contact: http://sebaro.pro/contact
  31.  
  32. */
  33.  
  34.  
  35. (function() {
  36.  
  37.  
  38. // ==========Variables========== //
  39.  
  40. // Userscript
  41. var userscript = 'LinkTube';
  42.  
  43. // Page
  44. var page = {win: window, doc: window.document, url: window.location.href};
  45.  
  46. // Contact
  47. var contact = 'http://sebaro.pro/contact';
  48.  
  49. // Warning
  50. var warning = 'Couldn\'t get the video link. Please report it <a href="' + contact + '">here</a>.';
  51.  
  52. // Options
  53. var option = {'secure': true};
  54.  
  55.  
  56. // ==========Fixes========== //
  57.  
  58. // Don't run on frames or iframes
  59. if (window.top != window.self) return;
  60.  
  61.  
  62. // ==========Functions========== //
  63.  
  64. function createMyElement(type, content) {
  65. var obj = document.createElement(type);
  66. if (type == 'div') {
  67. if (content) obj.innerHTML = content;
  68. }
  69. return obj;
  70. }
  71.  
  72. function getMyElement(element, get, tag) {
  73. var obj;
  74. if (get == 'parent') obj = element.parentNode;
  75. else if (get == 'source') {
  76. obj = element.src;
  77. if (!obj) {
  78. for (var i = 0; i < element.attributes.length; i++) {
  79. if (element.attributes[i].name.match(/^data.*src$/)) {
  80. obj = element.attributes[i].value;
  81. break;
  82. }
  83. }
  84. }
  85. }
  86. else if (get == 'name') obj = element.name;
  87. else if (get == 'value') obj = element.value;
  88. else if (get == 'children') obj = element.getElementsByTagName(tag);
  89. return obj;
  90. }
  91.  
  92. function modifyMyElement(obj, type, content, clear) {
  93. if (type == 'div') {
  94. if (content) obj.innerHTML = content;
  95. }
  96. if (clear) {
  97. if (obj.hasChildNodes()) {
  98. while (obj.childNodes.length >= 1) {
  99. obj.removeChild(obj.firstChild);
  100. }
  101. }
  102. }
  103. }
  104.  
  105. function styleMyElement(obj, styles) {
  106. for (var property in styles) {
  107. if (styles.hasOwnProperty(property)) obj.style[property] = styles[property];
  108. }
  109. }
  110.  
  111. function appendMyElement(parent, child) {
  112. if (parent == 'body') document.body.appendChild(child);
  113. else parent.appendChild(child);
  114. }
  115.  
  116. function removeMyElement(parent, child) {
  117. if (parent == 'body') document.body.removeChild(child);
  118. else parent.removeChild(child);
  119. }
  120.  
  121. function replaceMyElement(parent, orphan, child) {
  122. parent.replaceChild(orphan, child);
  123. }
  124.  
  125. function embedMyLinks(element) {
  126. var elements;
  127. if (element == 'iframe') elements = iframeElements;
  128. else if (element == 'object') elements = objectElements;
  129. else if (element == 'embed') elements = embedElements;
  130. var child, parent, video, param, name;
  131. var foundSite;
  132. var linkID, videoID, videoLink, videoURL;
  133. var myScriptLogo = [];
  134. myScriptLogo[element] = [];
  135. var myScriptMess = [];
  136. myScriptMess[element] = [];
  137. var myLinkWindow = [];
  138. myLinkWindow[element] = [];
  139. for (var e = elements.length - 1; e >= 0; e--) {
  140. foundSite = false;
  141. child = elements[e];
  142. parent = getMyElement(child, 'parent', '');
  143. if (element == 'iframe' || element == 'embed') {
  144. video = getMyElement(child, 'source', '');
  145. }
  146. else if (element == 'object') {
  147. params = getMyElement(child, 'children', 'param');
  148. for (var p = 0; p < params.length; p++) {
  149. name = getMyElement(params[p], 'name', '');
  150. if (name == 'movie' || name == 'src' || name == 'flashvars') {
  151. video = getMyElement(params[p], 'value', '');
  152. if (!video) video = getMyElement(params[p], 'source', '');
  153. }
  154. }
  155. }
  156. if (video) {
  157. for (var l = 0; l < linkParsers.length; l++) {
  158. if (video.match(linkParsers[l]['source'])) {
  159. foundSite = true;
  160. linkID = l;
  161. break;
  162. }
  163. }
  164. }
  165. if (foundSite) {
  166. myScriptLogo[element][e] = createMyElement('div', userscript);
  167. styleMyElement(myScriptLogo[element][e], {margin: '0px auto', padding: '10px', color: '#FFFFFF', fontSize: '20px', textAlign: 'center', textShadow: '#000000 -1px 1px 1px'});
  168. myScriptMess[element][e] = createMyElement('div', '');
  169. myLinkWindow[element][e] = createMyElement('div', '');
  170. appendMyElement(myLinkWindow[element][e], myScriptLogo[element][e]);
  171. appendMyElement(myLinkWindow[element][e], myScriptMess[element][e]);
  172. var childStyles = child.getAttribute('style');
  173. if (childStyles) {
  174. childStyles = childStyles.replace('absolute', 'relative');
  175. myLinkWindow[element][e].setAttribute('style', childStyles);
  176. styleMyElement(myLinkWindow[element][e], {border: '3px solid #F4F4F4', backgroundColor: 'transparent'});
  177. }
  178. else styleMyElement(myLinkWindow[element][e], {width: '100%', height: '100%', border: '3px solid #F4F4F4', backgroundColor: 'transparent'});
  179. styleMyElement(parent, {padding: '0px', height: '100%'});
  180. replaceMyElement(parent, myLinkWindow[element][e], child);
  181. videoID = video.match(linkParsers[linkID]['pattern']);
  182. videoID = (videoID) ? videoID[1] : null;
  183. if (videoID) {
  184. videoURL = linkParsers[linkID]['link'] + videoID;
  185. if (!option['secure']) videoURL = videoURL.replace(/^https/, 'http');
  186. videoLink = '<a href="' + videoURL + '" style="color:#336699;text-decoration:none;">' + videoURL + '</a>';
  187. styleMyElement(myScriptMess[element][e], {border: '1px solid #F4F4F4', margin: '5px', padding: '5px', backgroundColor: '#FFFFFF', color: '#00C000', textAlign: 'center', fontSize: '16px'});
  188. modifyMyElement(myScriptMess[element][e], 'div', videoLink, false);
  189. }
  190. else {
  191. styleMyElement(myScriptMess[element][e], {border: '1px solid #F4F4F4', margin: '5px', padding: '5px', backgroundColor: '#FFFFFF', color: '#AD0000', textAlign: 'center', fontSize: '16px'});
  192. modifyMyElement(myScriptMess[element][e], 'div', warning, false);
  193. }
  194. }
  195. }
  196.  
  197. }
  198.  
  199.  
  200. // ==========Websites========== //
  201.  
  202. /* Parsers */
  203. var linkParsers = [
  204. {'source': 'youtube(.com|-nocookie.com)/embed/(videoseries|\\?list)', 'pattern': 'list=(.*?)(&|$)', 'link': 'https://www.youtube.com/playlist?list='},
  205. {'source': 'youtube(.com|-nocookie.com)/embed/', 'pattern': '/embed/(.*?)(\\?|&|$)', 'link': 'https://www.youtube.com/watch?v='},
  206. {'source': 'youtube(.com|-nocookie.com)/v/', 'pattern': '/v/(.*?)(\\?|&|$)', 'link': 'https://www.youtube.com/watch?v='},
  207. {'source': 'dailymotion.com/embed/', 'pattern': '/video/(.*?)$', 'link': 'https://www.dailymotion.com/video/'},
  208. {'source': 'dailymotion.com/swf/(?!video)', 'pattern': '/swf/(.*?)$', 'link': 'https://www.dailymotion.com/video/'},
  209. {'source': 'dailymotion.com/swf/(?=video)', 'pattern': '/video/(.*?)$', 'link': 'https://www.dailymotion.com/video/'},
  210. {'source': 'vimeo.com/video/', 'pattern': '/video/(.*?)(\\?|&|$)', 'link': 'https://vimeo.com/'},
  211. {'source': 'vimeo.com/moogaloop', 'pattern': '/moogaloop.swf\\?clip_id=(.*?)(&|$)', 'link': 'https://vimeo.com/'},
  212. {'source': 'metacafe.com/embed/', 'pattern': '/embed/(.*?)/', 'link': 'https://www.metacafe.com/watch/'},
  213. {'source': 'metacafe.com/fplayer/', 'pattern': '/fplayer/(.*?)/', 'link': 'https://www.metacafe.com/watch/'},
  214. {'source': 'funnyordie.com/embed/', 'pattern': '/embed/(.*?)$', 'link': 'https://www.funnyordie.com/videos/'},
  215. {'source': 'vk.com/video', 'pattern': 'video_ext.php\\?(.*?)$', 'link': 'http://vk.com/video_ext.php?'},
  216. {'source': 'hostname=www.twitch.tv', 'pattern': 'channel=(.*?)(&|$)', 'link': 'http://www.twitch.tv/'}
  217. ];
  218.  
  219. var iframeElements;
  220. var objectElements;
  221. var embedElements;
  222.  
  223. function LinkTube() {
  224.  
  225. /* IFrame */
  226. iframeElements = getMyElement(document, 'children', 'iframe');
  227. if (iframeElements.length > 0 ) embedMyLinks('iframe');
  228.  
  229. /* Object */
  230. objectElements = getMyElement(document, 'children', 'object');
  231. if (objectElements.length > 0 ) embedMyLinks('object');
  232.  
  233. /* Embed */
  234. embedElements = getMyElement(document, 'children', 'embed');
  235. if (embedElements.length > 0 ) embedMyLinks('embed');
  236.  
  237. }
  238.  
  239.  
  240. // ==========Run========== //
  241.  
  242. LinkTube();
  243.  
  244. page.win.setInterval(function() {
  245. if (page.url != page.win.location.href) {
  246. page.doc = page.win.document;
  247. page.url = page.win.location.href;
  248. LinkTube();
  249. }
  250. }, 500);
  251.  
  252.  
  253. })();