🏠 Home 

LinkTube

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


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