Advertisement
Guest User

Untitled

a guest
Nov 16th, 2024
55
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name        Flickr Original Link
  3. // @namespace   https://greasyfork.org/scripts/1190-flickr-original-link
  4. // @include     /flickr\.com/
  5. // @version     6.0.1
  6. // @grant       GM_getValue
  7. // @grant       GM_setValue
  8. // @grant       GM_addStyle
  9. // @grant       GM_xmlhttpRequest
  10. // @require https://code.jquery.com/jquery-3.3.1.min.js
  11. // @description  Show direct links to download biggest Flickr image available and some other sizes.
  12. // @downloadURL https://update.greasyfork.org/scripts/1190/Flickr%20Original%20Link.user.js
  13. // @updateURL https://update.greasyfork.org/scripts/1190/Flickr%20Original%20Link.meta.js
  14. // ==/UserScript==
  15.  
  16. // THIS VERSION:
  17. // - bugfix: Replaces $.get() calls with GM_xmlhttpRequest to workaround the flickr.com CORS settings enforced by the browser. Now direct download links in albums are (more) reliable.
  18. // - user-interface: Removes the "DOWNLOAD" text from some pages, leaving only the image size text + colored background. TODO: two occurrences remaining, but I did not see them yet.
  19. // - enhancement: Moves the download links of the single-image page from down-below-hard-to-find up, below the image.
  20. // - dev: Code is formatted automatically by the Templatemonkey editor
  21. // - dev: Some comments and code cleanup while I was decyphering it. Far from clean, but it's approachable.
  22.  
  23. var postfix = "_d.jpg";
  24. var prefix = "DOWNLOAD ";
  25. var isChecked_openLink = "";
  26. var isChecked_alwaysShow = "";
  27. var key_openLink = "flickr_openLink";
  28. var key_alwaysShow = "flickr_alwaysShow";
  29. var value_openLink = false;
  30. var value_alwaysShow = false;
  31. var imageSizeOrder = ["9k","8k","7k","6k","5k","4k","3k","2k","o", "k", "h", "l","b", "c", "z"];
  32. var globalObserver = null;
  33.  
  34. function log(s) {
  35.     console.log(s);
  36. }
  37. log("Begin flickr script");
  38.  
  39. function getSetting() {
  40.     log("Begin get settings");
  41.     value_openLink = GM_getValue(key_openLink, false);
  42.     value_alwaysShow = GM_getValue(key_alwaysShow, false);
  43.     if (value_openLink) {
  44.         postfix = ".";
  45.         isChecked_openLink = ' checked="checked" ';
  46.         prefix = "OPEN ";
  47.     }
  48.     else {
  49.         postfix = "_d.";
  50.         isChecked_openLink = "";
  51.         prefix = "DOWNLOAD ";
  52.     }
  53.     if (value_alwaysShow) {
  54.         isChecked_alwaysShow = ' checked="checked" ';
  55.     }
  56.     else {
  57.         isChecked_alwaysShow = "";
  58.     }
  59. }
  60.  
  61. function checkAlwaysShow() {
  62.     if (value_alwaysShow) {
  63.         $('div.interaction-view').css('opacity', '1');
  64.     }
  65.     $('div.interaction-bar').css('bottom', '1.1em');
  66. }
  67.  
  68. // Add extra functionality in the single-photo page.
  69. function action_single_page() {
  70.     if ($('.commonButton').length > 0) {
  71.         // The download links have already been added.
  72.         return false;
  73.     }
  74.     var action = function (sourceCode) {
  75.         var sizes = sourceCode.match(/modelExport: {.+?"sizes":{.+?}}/i);
  76.         var mSize = sizes[0].match(/"width":"?\d+"?,"height":"?\d+"?,/ig);
  77.         var mLink = sizes[0].match(/"displayUrl":"[^"]+"/ig);
  78.         var length = mLink.length;
  79.         for (var k = 0; k < length; k++) {
  80.             mSize[k] = mSize[k].replace(/"width":(\d+),"height":(\d+),/i, "$1 x $2");
  81.             mLink[k] = mLink[k].replace(/"displayUrl":"([^"]+)"/i, "$1").replace(/\\/g, "").replace(/(_[0-9a-z]+)\.([a-z]{3,4})/i, '$1' + postfix + '$2');
  82.         }
  83.         var str = '<div style="width:100%; text-align:center;">';
  84.         for (k = Math.max(0, length - 7); k < length; k++) {
  85.             var c = (k == length - 1) ? 'bigButton' : 'smallButton';
  86.             str += '<a class="commonButton ' + c + '" href="' + mLink[k] + '">' + mSize[k] + ' px</a>';
  87.         }
  88.         str += '</div>';
  89.         var e = document.createElement('div');
  90.         e.innerHTML = str;
  91.         var insertLocation = $('.sub-photo-container');
  92.         insertLocation.prepend(e.firstChild);
  93.     };
  94.     $.get(document.URL, action);
  95. }
  96.  
  97. function addDownloadLinksToAlbumPhotos(data) {
  98.     if (data === null) {
  99.         log("data is null");
  100.         return;
  101.     }
  102.     var sizes = data.match(/"sizes":.+?}}/ig);
  103.     if (sizes === null) {
  104.         log("sizes is null");
  105.         return;
  106.     }
  107.     var dates = data.match(/"datePosted":"\d+"/ig);
  108.     if (dates == null) {
  109.         log("cannot find any dates");
  110.     }
  111.     var e2;
  112.     if (type == 'album') {
  113.         e2 = $('div.photo-card-view div.foot');
  114.     } else {
  115.         e2 = $('div.photo-list-photo-view');
  116.     }
  117.     log("Number of photo in this page: "+e2.length);
  118.     for (var index = 0; index < e2.length; index++) {
  119.         var e = $(e2[index]);
  120.         if (e.find('.myFuckingLink').filter(':first').length > 0) {
  121.             // Already added.
  122.             continue;
  123.         }
  124.         e.html(e.html() + '<a class="myFuckingLink"></a>');
  125.         for (var i = 0; i < imageSizeOrder.length; ++i) {
  126.             var photo = sizes[index].match(new RegExp('"' + imageSizeOrder[i] + '".*?:{"displayUrl":"([^"]+)","width":(\\d+),"height":(\\d+)', "i"));
  127.             if (photo === null) continue;
  128.  
  129.             var b = e.find('.myFuckingLink');
  130.             b.attr('href', photo[1].replace(/\\/g, "").replace(/(_[0-9a-z]+)\.([a-z]{3,4})/i, '$1' + postfix + '$2'));
  131.  
  132.             var timestamp = dates[index].match(/\d+/i);
  133.             var t = new Date((new Number(timestamp)) * 1000);
  134.             b.attr('title', prefix + photo[2] + " x " + photo[3] + " | Upload: " + t.toLocaleDateString());
  135.  
  136.             b.html(photo[2] + " x " + photo[3]);
  137.             break;
  138.         }
  139.     }
  140. }
  141.  
  142. function action_normal_page(theType) {
  143.     var target = $('#content')[0];
  144.     var config = {
  145.         childList: true,
  146.         subtree: true,
  147.     };
  148.     var prevUrl = "none";
  149.     var prevThumbLength = 0;
  150.     var sourceCode = null;
  151.  
  152.     var action = function (x) {
  153.         log('#content changed ' + x);
  154.         var e3;
  155.         if (x == 'album') {
  156.             e3 = $('div.photo-card-view');
  157.         } else {
  158.             e3 = $('div.photo-list-photo-view');
  159.         }
  160.         if (document.URL == prevUrl) {
  161.             if (e3.length == prevThumbLength) return false; // number of thumbnail is not change, no need to process further
  162.             checkAlwaysShow();
  163.             prevThumbLength = e3.length;
  164.             log("Number of thumb: " + prevThumbLength);
  165.             addDownloadLinksToAlbumPhotos(sourceCode);
  166.         } else {
  167.             var e1 = e3.find('a').filter(':first');
  168.             if (e1.length < 1) return false; // not found any link to valid single image page
  169.             checkAlwaysShow();
  170.             // get full source code for this page
  171.             sourceCode = null;
  172.             prevUrl = document.URL;
  173.             var link1 = e1.attr('href');
  174.             console.time("GetSource");
  175.             $('#content').append('<div id="loadingIndicator" style="position:fixed;left:5px;bottom:2em;display:block;background-color:pink;border:solid;padding:3px">Getting original link<br>Please wait...</div>');
  176.             log("Getting page of first photo: " + link1);
  177.             GM_xmlhttpRequest({
  178.                 method: "GET",
  179.                 url: link1,
  180.                 onload: function(response) {
  181.                     log("Got page of first photo");
  182.                     // Processing single image page source to get entry-type link
  183.                     var link2 = 'https://flickr.com' + response.responseText.match(/<a\s+class=.+?entry-type.+?href='([^']+)/i)[1];
  184.                     link2 = link2.replace("/albums/", "/sets/");
  185.                     log("Begin get source 2: " + link2);
  186.                     GM_xmlhttpRequest({
  187.                         method: "GET",
  188.                         url: link2,
  189.                         onload: function(response) {
  190.                             // Processing page source to get image links
  191.                             log("Got final source: " + link2);
  192.                             console.timeEnd("GetSource");
  193.                             $('#loadingIndicator').remove();
  194.                             addDownloadLinksToAlbumPhotos(response.responseText);
  195.                         },
  196.                         onerror: function(response) {
  197.                             log("Failed getting second? page: " + response);
  198.                         },
  199.                     });
  200.                 },
  201.                 onerror: function(response) {
  202.                     log("Failed getting first photo page: " + response);
  203.                 },
  204.             });
  205.         }
  206.     };
  207.     action(theType);
  208.     globalObserver = new MutationObserver(function (mutations, ob) {
  209.         action(theType);
  210.     });
  211.     globalObserver.observe(target, config);
  212. }
  213.  
  214. function flickr_mouseenter() {
  215.     var e = $(this);
  216.     if (e.find('.myFuckingLink').filter(':first').length > 0) {
  217.         e.off('mouseenter');
  218.         return false;
  219.     }
  220.     var url = e.find('a').filter(':first').attr('href');
  221.     if (typeof url == "undefined" || url === null) return false;
  222.     e.append('<a class="myFuckingLink">(Link loading...)</a>');
  223.     $.get(url, function (data) {
  224.         var photo = data.match(/"displayUrl":"([^"]+)","width":(\d+),"height":(\d+)[^}]+}}/i);
  225.         var link = photo[1].replace(/\\/g, "").replace(/(_[0-9a-z]+)\.([a-z]{3,4})/i, '$1' + postfix + '$2');
  226.         var text = prefix + photo[2] + " x " + photo[3] + " Upload: ";
  227.         var b = e.find('.myFuckingLink');
  228.         b.attr('href', link);
  229.         b.attr('title', text);
  230.         b.html(text);
  231.     });
  232. }
  233.  
  234. function action_hover_page() {
  235.     var target = $('body')[0];
  236.     var config = {
  237.         childList: true,
  238.         subtree: true,
  239.     };
  240.     var prevLength = 0;
  241.     globalObserver = new MutationObserver(function (mutations, ob) {
  242.         var e = $('div.photo-list-photo-view');
  243.         if (e.length == prevLength) return false; // no new Thumbnail, don't do anything
  244.         log("Number of thumb: " + e.length);
  245.         prevLength = e.length;
  246.         checkAlwaysShow();
  247.         e.mouseenter(flickr_mouseenter);
  248.     });
  249.     globalObserver.observe(target, config);
  250. }
  251.  
  252. function pageType() {
  253.     var t = "none";
  254.     var htmlClass = $('html').attr('class');
  255.     console.log("HTML class: " + htmlClass);
  256.     if (htmlClass.match(/html-photo-page.+scrappy-view/i) !== null) t = 'single';
  257.     else if (htmlClass.match(/html-(search-photos-unified|group-pool)-page-view/i) !== null) t = 'hover';
  258.     else if ($('div.photo-list-photo-view').filter(':first').length > 0) t = 'normal';
  259.     else if ($('div.photo-list-view').filter(':first').length > 0) t = 'album';
  260.     console.log("Page type: " + t);
  261.     return t;
  262. }
  263.  
  264. var prevType = "none";
  265. var type = "none";
  266. var oldUrl = "none";
  267. var count = 0;
  268.  
  269. function kickStart() {
  270.     oldUrl = document.URL;
  271.     type = pageType();
  272.     getSetting();
  273.     checkAlwaysShow();
  274.  
  275.     var strCss = "";
  276.     if (type == 'album') {
  277.         strCss += ".myFuckingLink{position:absolute;z-index:999999;left:5px;bottom:0px;width:100%;display:block;background-color: lightgreen;border-radius: 2px;}";
  278.     } else {
  279.         strCss += ".myFuckingLink{position:absolute;z-index:999999;left:3px;bottom:0px;width:100%;display:block;background-color: lightgreen;color:white!important;}";
  280.     }
  281.     strCss += ".myFuckingLink:hover{background-color:rgba(100, 100, 255,0.65)!important}";
  282.     strCss += ".commonButton{display: inline-block;border-radius: 0.5em;margin: 0.2em;padding: 0.5em;font-size: 90%;height: fit-content;}";
  283.     strCss += ".bigButton{background-color: lightgreen}";
  284.     strCss += ".smallButton{background-color:pink}";
  285.     GM_addStyle(strCss);
  286.  
  287.     // Install the settings functionality at the top of the page.
  288.     $('.myOptionBox').remove();
  289.     $('ul.nav-menu:first').append('<li class="myOptionBox"><div style="color:pink;padding:1px"><input id="optionbox_openLink" type="checkbox"' + isChecked_openLink + 'style="margin:2px"/>Open image link in browser<br><input id="optionbox_alwaysShow" type="checkbox"' + isChecked_alwaysShow + 'style="margin:2px"/>Always show image information in Photostream</div></li>');
  290.     $('#optionbox_openLink').change(function () {
  291.         GM_setValue(key_openLink, $(this).prop('checked'));
  292.     });
  293.     $('#optionbox_alwaysShow').change(function () {
  294.         GM_setValue(key_alwaysShow, $(this).prop('checked'));
  295.     });
  296.  
  297.     // Change the page.
  298.     if (type == 'single') action_single_page();
  299.     else if (type == 'normal' || type == 'album') action_normal_page(type);
  300.     else if (type == 'hover') action_hover_page();
  301. }
  302.  
  303. log("Preparing to run kickStart(), which decides what shall be done");
  304. var timestamp = "1469473824";
  305. var number = new Number(timestamp);
  306. var t = new Date(number * 1000);
  307. log("Time number: " + t.toLocaleDateString('vi-VN'));
  308.  
  309. kickStart();
  310.  
  311. // Run kickStart whenever the URL changes.
  312. var target = $('html')[0];
  313. var config = {
  314.     childList: false,
  315.     attributes: true,
  316. };
  317. var observer = new MutationObserver(function (mutations, ob) {
  318.     if (oldUrl == document.URL) {
  319.         // We already kickStarted the current page.
  320.         return;
  321.     }
  322.     if (globalObserver !== null) globalObserver.disconnect();
  323.     kickStart();
  324. });
  325. observer.observe(target, config);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement