FapFun

Userscript for Motherless.com. Provide direct links for pictures and video files. Download all Images on one site with DownThemAll(firefox) or Download Master(Chrome).

As of 2016-05-14. See the latest version.

  1. // ==UserScript==
  2. // @name FapFun
  3. // @namespace https://greasyfork.org/scripts/7156-fapfun/code/FapFun.user.js
  4. // @description Userscript for Motherless.com. Provide direct links for pictures and video files. Download all Images on one site with DownThemAll(firefox) or Download Master(Chrome).
  5. // @require https://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js
  6. // @include htt*://motherless.com*
  7. // @version 3.11
  8. // @grant GM_xmlhttpRequest
  9. // @grant GM_setClipboard
  10. // @grant GM_setValue
  11. // @grant GM_getValue
  12. // @grant GM_deleteValue
  13. // @grand UnsafeWindow
  14. // @author sodomgomora
  15. // @license GPLv3
  16. // ==/UserScript==
  17. // Some of this script based on Pornifier2 script by Jesscold
  18. // This script is realesed under GPL v3
  19. // Globals
  20. var debug = false;
  21. var images = [];
  22. var ids = [];
  23. var imagesUrl = [];
  24. var siteurls = [];
  25. var thisurl = '';
  26. // Start the magic
  27. main();
  28. function fapLog(log) {
  29. if (debug === true) {
  30. console.log(log);
  31. return;
  32. }
  33. return;
  34. }
  35. function main() {
  36. fapLog('entered main');
  37. // try to become Premium
  38. // setTimeout(function(){
  39. // unsafeWindow.__is_premium = true; //really motherless?
  40. // }, 500);
  41. thisurl = window.location.href;
  42. var inputList = document.createElement('input');
  43. inputList.type = 'button';
  44. inputList.value = 'Images URLs';
  45. inputList.name = 'imagesurl';
  46. inputList.onclick = getImageList;
  47. inputList.setAttribute('style', 'font-size:18px;position:fixed;top:100px;right:20px;z-index:10000;');
  48. document.body.appendChild(inputList);
  49. addSinglePreview();
  50. checkForPaginationLinks(function (hasOne) {
  51. fapLog('main: haseOne= ' + hasOne);
  52. if (hasOne > 0) {
  53. var inputAllImages = document.createElement('input');
  54. inputAllImages.type = 'button';
  55. inputAllImages.value = 'Get all Images';
  56. inputAllImages.name = 'getallimages';
  57. inputAllImages.onclick = getAllImages;
  58. inputAllImages.setAttribute('style', 'font-size:18px;position:fixed;top:140px;right:20px;z-index:10000;');
  59. document.body.appendChild(inputAllImages);
  60. }
  61. return;
  62. });
  63. return;
  64. }
  65. function addResetButton() {
  66. var resetButton = document.createElement('input');
  67. resetButton.type = 'button';
  68. resetButton.value = 'Reset';
  69. resetButton.name = 'deletevalue';
  70. resetButton.onclick = deleteGMValue;
  71. resetButton.setAttribute('style', 'font-size:18px;position:fixed;top:220px;right:20px;z-index:10000;');
  72. document.body.appendChild(resetButton);
  73. return;
  74. }
  75. function checkForPaginationLinks(cb) {
  76. var ret = '';
  77. ret = $('.pagination_link').contents().text();
  78. fapLog('checkForPaginationLinks: entered!');
  79. fapLog('checkForPaginationLinks: ret= ' + ret);
  80. if (ret === '') {
  81. cb(0);
  82. return;
  83. } else {
  84. cb(1);
  85. return;
  86. }
  87. }
  88. //----- Button onclick functions -----
  89.  
  90. function deleteGMValue() {
  91. fapLog('deleteGMValue: thisurl= ' + thisurl);
  92. GM_deleteValue(thisurl);
  93. $('input[name*=\'deletevalue\']').remove();
  94. $('input[name*=\'stopvalue\']').remove();
  95. }
  96. function getAllImages() {
  97. var href = '';
  98. var lasttmp = 0;
  99. ids = [
  100. ];
  101. href = window.location.href;
  102. href = href.replace(/^(http|https):\/\//i, '');
  103. fapLog('getAllImages: href= ' + href);
  104. var url = getUrl(href);
  105. if (GM_getValue(url.allsites) != undefined) {
  106. fapLog('getAllImages: was processed earlyer!');
  107. addResetButton();
  108. displayOverlay(imagesUrl, 'lasti', url.allsites);
  109. thisurl = url.allsites;
  110. return;
  111. }
  112. thisurl = url.allsites;
  113. sneakyXHR(url.onesite, function (src) {
  114. fapLog('getAllImages: callback from sneakyXHR = ' + src);
  115. var urlwithoutpagenumber = url.onesite.substring(0, url.onesite.length - 1);
  116. $firstids = $('<div>' + src + '</div');
  117. $firstsite = $('<div>' + src + '</div').find('.pagination_link a');
  118. fapLog($firstsite);
  119. $firstsite.each(function () {
  120. var tmp = parseInt($(this).text());
  121. if (tmp > lasttmp) {
  122. lasttmp = tmp;
  123. }
  124. });
  125. var headers = {
  126. 'Accept': 'text/xml',
  127. 'Range': 'bytes=0-300'
  128. };
  129. //load last paginationsite if last is realy true
  130. GM_xmlhttpRequest({
  131. method: 'get',
  132. 'url': urlwithoutpagenumber + lasttmp,
  133. headers: $.extend({
  134. }, {
  135. 'User-agent': 'Mozilla/4.0',
  136. 'Accept': 'text/xml',
  137. 'Range': 'bytes=0-300',
  138. 'Cookie': document.cookie
  139. }, headers || {
  140. }),
  141. onload: function (responseDetails) {
  142. var lastsitetmp = 1;
  143. var text = responseDetails.responseText;
  144. $lastsite = $('<div>' + text + '</div').find('.pagination_link a');
  145. fapLog($lastsite);
  146. $lastsite.each(function () {
  147. var tmp = parseInt($(this).text());
  148. if (tmp > lastsitetmp) {
  149. lastsitetmp = tmp;
  150. }
  151. });
  152. fapLog('getAllImages: lasttmp= ' + lasttmp + ' lastsitetmp=' + lastsitetmp);
  153. if (lasttmp < lastsitetmp) {
  154. lasttmp = lastsitetmp;
  155. }
  156. $test = $firstids.find('img[src^="http://cdn.thumbs.motherlessmedia.com/thumbs/"]');
  157. $test.each(function () {
  158. try {
  159. var id = $(this).attr('data-strip-src').match('thumbs/([^.]+).\\w');
  160. }
  161. catch (err) {
  162. return;
  163. }
  164. ids.push(id[1]);
  165. });
  166. fapLog('getAllImages: lasttmp= ' + lasttmp);
  167. //paginationsite shown but has no link
  168. if (lasttmp == 0) {
  169. getImages('getallimages', ids);
  170. return;
  171. }
  172. var urlwithoutpagenumber = url.onesite.substring(0, url.onesite.length - 1);
  173. for (var i = 2; i < lasttmp + 1; i++) {
  174. var lenght = siteurls.push(urlwithoutpagenumber + i);
  175. }
  176. fapLog('getAllImages: siteURLs= ' + siteurls);
  177. addStop();
  178. parralelizeTask(siteurls, loopGetSites, 'getallimages', function () {
  179. getImages('getallimages', ids);
  180. ids = [];
  181. return;
  182. });
  183. }
  184. });
  185. }, 'get', {
  186. 'Accept': 'text/xml',
  187. 'Range': 'bytes=0-300' //grab first 3k
  188. });
  189. return;
  190. }
  191. // retrun URLs for user,group,galleries and search page
  192. function getUrl(href) {
  193. var url = '';
  194. var urlall = '';
  195. var parthref = '';
  196. var n = href.indexOf('?');
  197. if (n != -1) {
  198. parthref = href.substring(0, n);
  199. } else {
  200. parthref = href;
  201. }
  202. fapLog('getUrl: parthref= ' + parthref);
  203. var casesn = parthref.indexOf('/');
  204. var cases = parthref.substring(casesn + 1, casesn + 2);
  205. fapLog('getUrl: cases= ' + cases);
  206. switch (cases) {
  207. case 'G':
  208. var gup = parthref.substring(casesn + 3, parthref.lenght);
  209. fapLog('getUrl: gup= ' + gup);
  210. url = 'http://motherless.com/GI' + gup + '?page=1';
  211. urlall = 'http://motherless.com/GI' + gup;
  212. break;
  213. case 'g':
  214. var g = parthref.substring(casesn + 3, parthref.lenght);
  215. fapLog('getUrl: g= ' + g);
  216. url = 'http://motherless.com/gi' + g + '?page=1';
  217. urlall = 'http://motherless.com/gi' + g;
  218. break;
  219. case 'u':
  220. var u = parthref.substring(casesn, parthref.lenght);
  221. fapLog('getUrl: u= ' + u);
  222. url = 'http://motherless.com' + u + '?t=i&page=1';
  223. urlall = 'http://motherless.com' + u;
  224. break;
  225. case 't':
  226. var t = parthref.substring(casesn, parthref.lenght);
  227. fapLog('getUrl: t= ' + t);
  228. url = 'http://motherless.com' + t + '?range=0&size=0&sort=relevance&page=1';
  229. urlall = 'http://motherless.com' + t;
  230. break;
  231. }
  232. return {
  233. onesite: url,
  234. allsites: urlall
  235. };
  236. }
  237. function getImageList() {
  238. fapLog('getImageList: pressed');
  239. thisurl = window.location.href;
  240. if (thisurl.indexOf('?') == -1) {
  241. thisurl = thisurl + '?page=1';
  242. }
  243. if (GM_getValue(thisurl) != undefined) {
  244. addResetButton();
  245. displayOverlay(data = [], 'lasti', thisurl);
  246. return false;
  247. }
  248. getImages('imagesurl', images);
  249. return;
  250. }
  251. function getVideoUrl() {
  252. alert('not jet implemented!');
  253. return;
  254. }
  255. //-- handler for Overlay (jquery)
  256.  
  257. $(function () {
  258. $('body').click(function () {
  259. if ($('#overlay').length > 0) {
  260. removeOverlay();
  261. return;
  262. }
  263. });
  264. return;
  265. });
  266. function removeOverlay() {
  267. $('#overlay').remove();
  268. return;
  269. }
  270. // Get url for full image and add url under thumbnail
  271.  
  272. function addSinglePreview() {
  273. var data = [];
  274. var i = 0;
  275. var imgs = $('img[src^="http://cdn4.thumbs.motherlessmedia.com/thumbs/"]');
  276. if (typeof unsafeWindow.__fileurl != "undefined") {
  277. fapLog('Script url found: ' + unsafeWindow.__fileurl);
  278. var $wrap = $('.media-action-networks');
  279. fapLog('TEst' + $wrap.toSource());
  280. var videourl = $('<strong>Video URL: </strong><a href=\'' + unsafeWindow.__fileurl + '\' class=\'pop\'>Download</a>');
  281. $wrap.after(videourl);
  282. }
  283. fapLog('image urls found: ' + imgs.length);
  284. imgs.each(function () {
  285. var $wrap = $(this);
  286. if ($wrap.data('p2-preview')) {
  287. return;
  288. }
  289. $wrap.data('p2-preview', 'yep');
  290. var $a = $wrap.closest('a');
  291. var vid = $wrap.attr('src').match('thumbs/([^.]+).\\w');
  292. // test for video preview and not an image
  293. var vlink = vid[1];
  294. var n = vlink.indexOf('-');
  295. vlink = vlink.substring(n, vlink.length);
  296. fapLog('vlink: ' + vlink);
  297. // is a video
  298. if (vlink == '-small') {
  299. var videoClicky = $('<a href=\'javascript;\' class=\'p2-single-preview\'>Video URL</a>');
  300. $a.after(videoClicky);
  301. var href = $a.attr('href').match(/\.com\/(\w)(\w+)/) ? [
  302. RegExp.$1,
  303. RegExp.$2
  304. ] : false;
  305. videoClicky.click(function (e, single) {
  306. var $this = $currentSingle = $(this);
  307. $this.text('loading...');
  308. var id = $wrap.attr('data-strip-src').match('thumbs/([^.]+).\\w');
  309. var vl = id[1];
  310. var n = vl.indexOf('-');
  311. id[1] = vl.substring(0, n);
  312. fapLog('addSinglePreview: found url for video: ' + id[1]);
  313. if (!id) {
  314. $this.text('cant load :P');
  315. return;
  316. }
  317. var timer = setTimeout(function () {
  318. $this.text('cant load :P');
  319. }, 8000);
  320. var fs = new findSrc();
  321. fs.findVideoSrc(id[1], function (src) {
  322. $this.text('Show Video');
  323. clearTimeout(timer);
  324. if (single) {
  325. data = [src];
  326. } else {
  327. data.unshift(src);
  328. }
  329. fapLog('addSinglePreview: video src: ' + src.toSource());
  330. displayOverlay(data, 'video');
  331. });
  332. return false;
  333. });
  334. }
  335. else {
  336. try {
  337. var id = $wrap.attr('data-strip-src').match('thumbs/([^.]+).\\w');
  338. }
  339. catch (err) {
  340. fapLog(err.message);
  341. return;
  342. }
  343. images[i] = id[1];
  344. i++;
  345. fapLog('fill images: image=' + images[i - 1] + ' index=' + i);
  346. var imageClicky = $('<a href=\'javascript;\' class=\'p2-single-preview\'>View full size</a>');
  347. $a.after(imageClicky);
  348. var href = $a.attr('href').match(/\.com\/(\w)(\w+)/) ? [
  349. RegExp.$1,
  350. RegExp.$2
  351. ] : false;
  352. imageClicky.click(function (e, single) {
  353. var $this = $currentSingle = $(this);
  354. $this.text('loading...');
  355. fapLog('found url for image: ' + id[1]);
  356. if (!id) {
  357. $this.text('cant load :P');
  358. return;
  359. }
  360. var timer = setTimeout(function () {
  361. $this.text('cant load :P');
  362. }, 8000);
  363. var fs = new findSrc();
  364. fs.findImgSrc(id[1], function (src) {
  365. $this.text('View full size');
  366. clearTimeout(timer);
  367. if (single) {
  368. data = [
  369. src
  370. ];
  371. } else {
  372. data.unshift(src);
  373. }
  374. fapLog('addSinglePreview: image src: ' + src.toSource());
  375. displayOverlay(data, 'image');
  376. });
  377. return false;
  378. });
  379. }
  380. });
  381. }
  382. function getImages(buttonname, arrimg) {
  383. fapLog('getImages: arrimg.length=' + arrimg.length);
  384. fapLog(arrimg);
  385. $button = $('input[name*=\'' + buttonname + '\']');
  386. $button.val('working...');
  387. if (arrimg.length > 0) {
  388. parralelizeTask(arrimg, loopFindImageSource, buttonname, function () {
  389. fapLog('getImages: iamgesUrl= ' + imagesUrl.toSource());
  390. arrimg = [];
  391. displayOverlay(imagesUrl, 'images', thisurl);
  392. imagesUrl = [];
  393. return;
  394. });
  395. }
  396. fapLog('getImages: last call for return');
  397. arrimg = [];
  398. return;
  399. }
  400. function findSrc() {
  401. this.findVideoSrc = function (id, cb) {
  402. var href = 'http://motherless.com/' + id;
  403. sneakyXHR(href, function (d) {
  404. fapLog('sneaky request all: ' + d.toSource());
  405. var url = d.match(/http:([^"]*).mp4/m) ? RegExp.$1 : " ";
  406. fapLog('findVideoSrc: ' + url);
  407. if (url) {
  408. cb({
  409. url: 'http:' + url + '.mp4'
  410. });
  411. }
  412. return;
  413. }, 'get', {
  414. 'Accept': 'text/xml',
  415. 'Range': 'bytes=0-300' //grab first 3k
  416. });
  417. return;
  418. };
  419. this.findImgSrc = function (id, cb) {
  420. var href = 'http://motherless.com/' + id + '?full';
  421. sneakyXHR(href, function (d) {
  422. var img = d.match(/property="og:image" content="([^"]+)"/im) ? RegExp.$1 : null;
  423. if (img) {
  424. cb({
  425. url: img
  426. });
  427. }
  428. return;
  429. }, 'get', {
  430. 'Accept': 'text/xml',
  431. 'Range': 'bytes=0-300' //grab first 3k
  432. });
  433. return;
  434. };
  435. }
  436. function sneakyXHR(url, cb, method, headers) {
  437. method = method || 'GET';
  438. fapLog('sneaky requesting: ' + url);
  439. setTimeout(function () {
  440. GM_xmlhttpRequest({
  441. method: method,
  442. url: url,
  443. headers: $.extend({
  444. }, {
  445. 'User-agent': 'Mozilla/4.0',
  446. 'Accept': 'text/xml',
  447. 'Range': 'bytes=0-300',
  448. 'Cookie': document.cookie
  449. }, headers || {
  450. }),
  451. onload: function (responseDetails) {
  452. var text = responseDetails.responseText;
  453. cb(text, responseDetails);
  454. }
  455. });
  456. }, 1);
  457. return;
  458. }
  459. // show the full image as overlay and shrink it to screen resolution
  460.  
  461. function displayOverlay(data, type, url) {
  462. var mywidht = window.innerWidth;
  463. var myheight = window.innerHeight;
  464. var html = '';
  465. fapLog('monitor resolution: ' + window.innerWidth + ':' + window.innerHeight);
  466. switch (type) {
  467. case 'lasti':
  468. fapLog('displayOverlay: lasti: url= ' + url);
  469. html = GM_getValue(url);
  470. GM_setClipboard(GM_getValue(url + 'clipboard'));
  471. break;
  472. case 'image':
  473. html = '<table id=\'overlay\'><tbody><tr><td><img src=\'' + data[0].url + '\' style=\'width:auto; hight:auto; max-height:' + myheight + 'px; max-width:' + mywidht + 'px\'></td></tr></tbody></table>';
  474. break;
  475. case 'video':
  476. html = '<table id=\'overlay\'><tbody><tr><td><a href=\'' + data[0].url + '\'>Video Link</a></td></tr></tbody></table>';
  477. break;
  478. case 'images':
  479. var clipboard = '';
  480. var count = 1;
  481. $('input[name*=\'getallimages\']').val('Get all Images');
  482. $('input[name*=\'imagesurl\']').val('Images URLs');
  483. html = '<table id=\'overlay\'><tbody><tr><td>';
  484. data.forEach(function (value) {
  485. html += '<a class=\'changeColorLink\' href=\'' + value + '\'>link ' + count + '</a> ';
  486. clipboard += value + ' ';
  487. count++;
  488. });
  489. html += '</td></tr></tbody></table>';
  490. GM_setClipboard(clipboard);
  491. GM_setValue(url, html.toString());
  492. GM_setValue(url + 'clipboard', clipboard.toString());
  493. break;
  494. }
  495. fapLog('displayOverlay: type= ' + type + ': html=' + html.toSource());
  496. setTimeout(function () {
  497. var $el = $(html).css({
  498. 'position': 'fixed',
  499. 'top': 0,
  500. 'left': 0,
  501. 'width': '90%',
  502. 'height': '100%',
  503. 'background-color': 'rgba(0,0,0,.7)',
  504. 'z-index': 10000,
  505. 'vertical-align': 'middle',
  506. 'text-align': 'center',
  507. 'color': '#fff',
  508. 'font-size': '30px',
  509. 'font-weight': 'bold',
  510. 'overflow': 'hidden',
  511. 'cursor': 'auto'
  512. });
  513. $('a.changeColorLink', $el).hover(function () {
  514. $(this).css('color', 'blue');
  515. }, function () {
  516. $(this).css('color', 'pink');
  517. });
  518. $el.appendTo('body');
  519. }, 50);
  520. return;
  521. }
  522. //----- PARALELLIZISE -----
  523. //paralellize for getting all sites within pagination
  524.  
  525. function loopGetSites(doneTask, value) {
  526. sneakyXHR(value, function (src) {
  527. $firstids = $('<div>' + src + '</div');
  528. $test = $firstids.find('img[src^="http://cdn4.thumbs.motherlessmedia.com/thumbs/"]');
  529. $test.each(function () {
  530. try {
  531. var id = $(this).attr('data-strip-src').match('thumbs/([^.]+).\\w');
  532. }
  533. catch (err) {
  534. fapLog(err.message);
  535. return;
  536. }
  537. if (id[1].lastIndexOf('-strip') != -1) {
  538. fapLog('loopGetSites: Falsche parameter. Enthält -strip');
  539. return;
  540. }
  541. ids.push(id[1]);
  542. return;
  543. });
  544. doneTask();
  545. return;
  546. }, 'get', {
  547. 'Range': 'bytes=0-3000' //grab first 3k);
  548. });
  549. }
  550. //function to parallelize the findImageSource function
  551.  
  552. function loopFindImageSource(doneTask, value) {
  553. var fs = new findSrc();
  554. fs.findImgSrc(value, function (src) {
  555. var i = 0;
  556. data = [src];
  557. imagesUrl.push(data[0].url);
  558. doneTask();
  559. return;
  560. });
  561. return;
  562. }
  563. //helper function for parralelize functions
  564.  
  565. function parralelizeTask(arr, fn, buttonname, done) {
  566. fapLog('parralelizeTask: arr= ' + arr);
  567. var total = arr.length;
  568. var maxtotal = total;
  569. var counttimeout = 0;
  570. fapLog('parralelizeTask: arr.length= ' + total);
  571. doneTask = function () {
  572. if (--total === 0) {
  573. done();
  574. return;
  575. }
  576. $('input[name*=\'' + buttonname + '\']').val('processed:' + total);
  577. return;
  578. };
  579. arr.forEach(function (value) {
  580. fn(doneTask, value);
  581. });
  582. return;
  583. }
  584.  
  585. function addStop() {
  586. var stopButton = document.createElement('input');
  587. stopButton.type = 'button';
  588. stopButton.value = 'Stop';
  589. stopButton.name = 'stopvalue';
  590. stopButton.onclick = stop;
  591. stopButton.setAttribute('style', 'font-size:18px;position:fixed;top:260px;right:20px;z-index:10000;');
  592. document.body.appendChild(stopButton);
  593. return;
  594. }
  595.  
  596. function stop() {
  597. displayOverlay(imagesUrl, 'images', thisurl);
  598. }