There are 14 previous versions of this script.
// ==UserScript==
// @name Flickr: Show All Sizes
// @namespace Jason Tank/Druidic
// @description Adds links to every available size of a Flickr image.
// @version 3.2
// @require http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js
// @match *://*.flickr.com/photos/*
// ==/UserScript==
// Summary: Links appear below the image's description on individual Flickr photo pages. They are fetched in the background, so an animated 'loading' message will appear until the links are ready.
// Based (somewhat) on http://userscripts.org/scripts/show/103073
// v1.0 - Initial script.
// v1.1 - Small visual tweaks.
// - Added links to new "Small 320" and "Medium 800" formats.
// v1.2 - Minor change to loading message.
// - More documentation in-script.
// v1.3 - "Large 1600" and "Large 2048" now supported.
// - More documentation.
// - Image links now rearrange by size if too many are available.
// v1.4 - More robust image-checking.
// v1.4.1 - Square 150 support.
// - Even MORE robust image-checking.
// v1.5 - Reorganized script, links. Trying to keep output on one line.
// - Links now have tooltips.
// - Redid image-checking using HTML to save info instead of the sometimes-buggy .data() jQuery method.
// - Thumbnail is now simply "Small 100". (But remains "Thumbnail" in tooltip.)
// v2.0 - Changed methodology. Rather than brute-force trying all possible files, just look at ONE image page and figure out what's available.
// - Moved from jQuery 1.6.2 to 1.7.2
// v2.1 - Fixed bug where Firefox would not show links. (Bug probably existed since 1.5!)
// - More documentation
// v2.2 - Even more documentation!!
// - Fixed an unclosed tag in the Medium 640 link.
// v2.3 - Clarified the error message and altered its appearance.
// - Simplied code.
// - Added a check for jQuery, so we don't have to load a second instance if it's already installed.
// - Added support for secure (https) pages.
// v2.4 - @namespace added.
// - Moved the NotOkToDeLoad variable initialization to a place where it would actually initialize! (oops)
// - @require added.
// - Added "?zz=1" to Medium 640 images so older photos can resize correctly.
// v2.5 - Compacted three @match commands into one.
// - Bumped up to jQuery 1.8.2
// - Tweaked error message, directing users to http://userscripts.org/scripts/discuss/111902
// v3.0 - Bumped up to jQuery 1.8.3
// - Turned off loading of larger sizes by default.
// v3.1 - Minor coding tweaks. (Flickr updated its interface, this extension still works with it!)
// v3.2 - Changed colors to match current Flickr look.
// - Minor CSS tweak to push Hack outside of a neighbor element's bounding box.
// - Bumped up to jQuery 2.0.0
// a function that loads jQuery and calls a callback function when jQuery has finished loading
// (This is necessary for Chromium, which doesn't support @require)
function addJQuery(mainScript) {
var script = document.createElement("script");
script.setAttribute("src", "//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js");
script.setAttribute('type', 'text/javascript');
script.addEventListener('load', function() {
var script = document.createElement("script");
script.textContent = "(" + mainScript.toString() + ")();";
document.body.appendChild(script);
}, false);
document.body.appendChild(script);
}
// the guts of this userscript
function flickrSizeHackMain() {
// Check if we're on the right type of page.
if($("div#main div#primary-column div#meta").length <= 0) {
return; // Not a photo page. No need to run.
}
//*//*//*//*//*//*//*//*//*//*//*//*//*//
// LOCAL STORAGE //
//*//*//*//*//*//*//*//*//*//*//*//*//*//
// Test for local storage.
function supports_html5_storage() {
try { return 'localStorage' in window && window['localStorage'] !== null; }
catch (e) { return false; }
}
// Determine if we're showing or hiding Larger sizes.
if(supports_html5_storage()) {
// We have localStorage. Load the stored info.
HideLARGE = localStorage["FlickrSizeHackHIDE"];
if(!HideLARGE) {
// There was nothing to load. Default to hiding Larger sizes.
HideLARGE = 1;
// Store this info.
localStorage["FlickrSizeHackHIDE"] = 1;
}
} else {
// No local storage. Default to showing Larger sizes (sorta).
HideLARGE = 0;
}
// Set aside variable for saving Larger image info for later retrieval.
var LargerImages = new Array();
//*//*//*//*//*//*//*//*//*//*//*//*//*//
// HTML AND CSS DISPLAY //
//*//*//*//*//*//*//*//*//*//*//*//*//*//
// Create the HTML for display.
var flickrSizeHackHTML = '<div id="FlickrSizeHack">' +
'<span id="Square" class="HackGroup">Square: ' +
'<a id="Hacksq" title="_s.jpg Square 75"></a>' +
'<a id="Hackq" title="_q.jpg Square 150"></a></span>' +
'<span id="Small" class="HackGroup">Small: ' +
'<a id="Hackt" title="_t.jpg Small 100 Thumbnail"></a>' +
'<a id="Hacks" title="_m.jpg Small 240"></a>' +
'<a id="Hackn" title="_n.jpg Small 320"></a></span>' +
'<span id="Medium" class="HackGroup">Medium: ' +
'<a id="Hackm" title=".jpg Medium 500"></a>' +
'<a id="Hackz" title="_z.jpg?zz=1 Medium 640"></a>' +
'<a id="Hackc" title="_c.jpg Medium 800"></a></span>' +
'<span id="Large" class="HackGroup">Large: ' +
'<a id="Hackl" title="_b.jpg Large 1024"></a>' +
'<a id="Hackh" title="_h.jpg Large 1600"></a>' +
'<a id="Hackk" title="_k.jpg Large 2048"></a></span>' +
'<span id="Original" class="HackGroup"> <a id="Hacko" title="_o.jpg Original Original Original"></a></span>' +
'<span class="HackLoading"><span class="L1">Loading</span> <span class="L2">all</span> <span class="L3">sizes...</span></span>' +
'</div><div id="FlickrSizeHackTemp"></div><div id="FlickrSizeHackMsg"></div>';
// Place the HTML after the photo's description.
$("div#main div#primary-column div#meta").after(flickrSizeHackHTML);
// Create HTML for the More/Toggle links.
var flickrSizeHackLargerHTML = '<span id="HackMore" title="Click to show links for larger images."></span>';
var flickrSizeHackToggleHTML = '<span id="HackTrue" class="HackToggle" title="Currently hiding larger images. Click to show them.">+</span><span id="HackFalse" class="HackToggle" title="Currently showing larger images. Click to hide them.">-</span>';
// CSS presentation for the grouping as a whole.
var wholeStyle = {"margin-bottom" : "10px"};
// CSS presentation for the links.
var linkStyle = {"border-width" : "1px",
"border-style" : "solid",
"border-color" : "#000",
"padding-left" : "2px",
"padding-right" : "2px",
"font-family" : "arial,sans-serif",
"background" : "#fff",
"margin-right" : "5px"};
// CSS presentation for the link groupings ("HackGroup").
var hackStyle = {"white-space" : "nowrap",
"background" : "#222",
"color" : "#fff",
"padding-left" : "2px"};
// Apply the CSS to the links and groups.
$("div#FlickrSizeHack").css(wholeStyle);
$("div#FlickrSizeHack a, div#FlickrSizeHack span.HackLoading").css(linkStyle);
$("div#FlickrSizeHack span.HackGroup").css(hackStyle);
// Fix link hovering color-change to behave like other links.
$("div#FlickrSizeHack a").hover(function() { $(this).css("background-color", "#0063dc"); }, function() { $(this).css("background-color", "#fff"); });
// Hide links and groups until we're ready to display them.
$("div#FlickrSizeHack a, span.HackGroup, div#FlickrSizeHackTemp").css("display", "none");
// CSS presentation for the Toggle/More links.
var HackMoreToggleCSS = {"background" : "#222",
"color" : "#fff",
"cursor" : "pointer",
"font-family" : "arial,sans-serif",
"padding-left" : "2px",
"padding-right" : "2px",
"margin-left" : "7px",
"margin-right" : "2px"};
// Animation of the 'loading' block.
var Lone = $("div#FlickrSizeHack span.L1");
var Ltwo = $("div#FlickrSizeHack span.L2");
var Lthr = $("div#FlickrSizeHack span.L3");
function doFading() {
Lone.fadeOut(200);
Lone.fadeIn(200);
Ltwo.delay(100);
Ltwo.fadeOut(200);
Ltwo.fadeIn(200);
Lthr.delay(300);
Lthr.fadeOut(200);
Lthr.fadeIn(200, doFading);
}
doFading();
//*//*//*//*//*//*//*//*//*//*//*//*//*//
// LOAD IMAGE INFO TO PAGE //
//*//*//*//*//*//*//*//*//*//*//*//*//*//
// Flickr size pages are accessed via URLs ending in sq, q, t, s, n, m, z, c, l, k, h, o.
var sizes = "qtsnmzcl"; // These sizes (and sq) all follow the same image filename format.
var otherSizes = "kho"; // These sizes have different image filename formats.
// Parse the current URL into usable chunks.
var Url = window.location + '';
var mm = Url.split('/');
var domain = mm[2];
var user = mm[4];
var photo = mm[5];
// Create a base URL to add sizes to.
var URL = '//' + domain + '/photos/' + user + '/' + photo + '/sizes/';
// Set a counter variable. (If positive, there are more images to be dealt with.)
var NotOkToDeLoad = 0;
// Load Square 75 size (the most likely to exist). Only grab the list of sizes and the image.
Url = URL + "sq";
$("#FlickrSizeHackTemp").load(Url + " ol.sizes-list, div#allsizes-photo", function() { parseSizesPage() });
// This script is called after the 'Square 75' page is loaded.
function parseSizesPage() {
var url = $("#FlickrSizeHackTemp").find("img").attr("src"); // Find the SRC of the Square 75 image
var pattern = new RegExp("(^.*?)_[a-z]\.jpg"); // Find the basic image filename
var l = url.length;
var mm = pattern.exec(url);
if(mm) { // See corresponding 'else' below
var srcBase = url.substr(0, l-6);
activateLink("sq", srcBase); // Load Square 75 link.
$("#FlickrSizeHackTemp").find("a").each(function() { // Loop thorough each link from the sizes page.
var url = $(this).attr("href"); // Find the link to the image's size page
var pattern = new RegExp("sizes/([" + sizes + "])/$");
var otherPattern = new RegExp("sizes/([" + otherSizes + "])/$");
var sz = pattern.exec(url);
if(sz) { // See if the size is one of the standard-format pages
activateLink(sz[1], srcBase); // ... and turn it on
} else {
sz = otherPattern.exec(url); // ... otherwise, try and see if it's one of the other formats
if(sz && (HideLARGE < 1)) { // (load them now if we're toggled that way)
NotOkToDeLoad++; // Increment counter variable
$("a#Hack" + sz[1]).load(URL + sz[1] + " div#allsizes-photo", function() { activateBigLink(sz[1], 1); });
} else if (sz) {
LargerImages.push(sz[1]); // (save image info for later use if we're toggled THAT way)
}
}
});
if(LargerImages.length > 0) {
// We have some larger images we can show later. Display [More] link.
$("div#FlickrSizeHack").append(flickrSizeHackLargerHTML);
$("span#HackMore").css(HackMoreToggleCSS).text(String(LargerImages.length) + " More");
$("span#HackMore").click(function() { showLargerImages(); } );
}
} else {
//
//
// This is highly unlikely, but means that Flickr has greatly changed its filename format!!
//
//
$("#FlickrSizeHack").html("<em><span>Flickr: Show All Sizes</span> had an error: could not extract image URLs. Please consider <a href=\"http://userscripts.org/scripts/discuss/111902\">reporting</a> this error to the script author.</em>");
$("#FlickrSizeHack em span").css("font-weight", "bold");
$("#FlickrSizeHack em").css({"background" : "#eee",
"border-width" : "1px",
"border-color" : "#cce",
"border-style" : "solid",
"padding" : "1px",
"font-style" : "italic"});
}
$("#FlickrSizeHackTemp").remove(); // Delete Temp block.
if(!NotOkToDeLoad) {
$("#FlickrSizeHack span.HackLoading").remove(); // Delete 'loading' block.
doToggleHTML();
}
}
//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//
// 'ACTIVATE' FUNCTIONS (used by parseSizePages) //
//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//
// Used to set up the basic-format links
function activateLink(sz, src) {
var SPAN = "a#Hack" + sz; // Figure out which <a> we're affecting
var info = $(SPAN).attr("title").split(" "); // Get the data in the title
doIt(SPAN, info, src + info[0]) // Call doIt to set all the info
}
// Used to set up the alternate-format links
function activateBigLink(sz, flag) {
var SPAN = "a#Hack" + sz; // Figure out which <a> we're affecting
var SRC = $(SPAN).find("img").attr("src"); // Find the <img>'s src
$(SPAN).find("div").remove(); // Remove the <div> (with <img> inside)
var info = $(SPAN).attr("title").split(" "); // Get the data in the title
doIt(SPAN, info, SRC); // Call doIt to set all the info
NotOkToDeLoad--; // Decrement counter variable
if(flag && !NotOkToDeLoad) {
$("#FlickrSizeHack span.HackLoading").remove(); // ... if down to 0, then delete 'loading' block
doToggleHTML();
}
}
// Internally used by both 'activate' functions to do all the dirty work.
function doIt(SPAN, info, href) {
$(SPAN).attr("href", href); // Set the href to the src
$(SPAN).text(info[2]); // Set the link text to the appropriate info
$("#"+info[1]).css("display", "inline"); // Make the HackGroup visible (Square, Small, etc.)
if(info[3]) {
title = info[3]; // If there's a special tooltip, use it
} else {
title = info[1] + " " + info[2]; // ... otherwise, the tooltip is the group + size
}
$(SPAN).attr("title", title); // Set the tooltip
$(SPAN).css("display", "inline"); // Make the <a> visible
}
//*//*//*//*//*//*//*//*//*//*//*//*//*//
// MORE AND TOGGLE LINKS. //
//*//*//*//*//*//*//*//*//*//*//*//*//*//
// Used by [More] link to load the larger images.
function showLargerImages() {
// Internal function, used to provide 'closure' for the sz variable.
function doActivateBig(sz) {
$("a#Hack" + sz).load(URL + sz + " div#allsizes-photo", function() { activateBigLink(sz, 0); });
}
// Go through each detected image and load them.
for(var x = 0;x < LargerImages.length;++x) {
var sz = LargerImages[x];
doActivateBig(sz);
}
LargerImages = 0;
// Get rid of the [More] link.
$("#HackMore").css("background", "#f08").fadeOut(450);
}
// Display the [-] [+] toggle links.
function doToggleHTML() {
// No need to call if we don't have localStorage.
if(HideLARGE) {
$("#FlickrSizeHack").append(flickrSizeHackToggleHTML); // Display the links
if(HideLARGE > 0) {
$("#HackFalse").css("display", "none"); // If 1, we're hiding. Show [+]
} else {
$("#HackTrue").css("display", "none"); // If -1, we're showing. Show [-]
}
$(".HackToggle").css(HackMoreToggleCSS).click(function() { doToggle(); } );
}
}
// Used by the [-] [+] toggle links.
function doToggle() {
var msg;
if(HideLARGE > 0) {
HideLARGE = -1; // If 1, we're currently hiding. Hide [+], show [-]
$("#HackTrue").css("display", "none");
$("#HackFalse").css("display", "inline").css(HackMoreToggleCSS);
msg = "Larger images, when available, will now always be displayed.";
if(LargerImages) {
showLargerImages(); // Show hidden images.
}
} else {
HideLARGE = 1; // If -1, we're currently showing. Hide [-], show [+]
$("#HackTrue").css("display", "inline").css(HackMoreToggleCSS);
$("#HackFalse").css("display", "none");
msg = "Larger images, when available, will no longer be displayed. (You can hit the 'More' link to see them.)";
}
// Save the new info to localStorage.
localStorage["FlickrSizeHackHIDE"] = HideLARGE;
// Display a message to the user.
displayToggleMsg(msg);
}
// Tell the user they clicked on the Toggle link, and what that now means.
function displayToggleMsg(msg) {
var w = Math.max(1, ($(window).width() / 2) - 140); // Calculate left position
var h = Math.max(1, ($(window).height() / 2) - 100); // Calculate top position.
$("#FlickrSizeHackMsg").stop(true, true).css({position: "fixed", top: h + "px", left: w + "px", zIndex: "10",
backgroundColor: "#eee", border: "2px solid #cce", padding: "10px",
color: "#000", fontSize: "16px", fontWeight: "bold", textAlign: "center",
cursor: "help", width: "280px"}).text(msg);
$("#FlickrSizeHackMsg").fadeIn(250).delay(3000).fadeOut(2000); // Show for three seconds, then fade for two.
$("#FlickrSizeHackMsg").click(function() {
$(this).stop(true).fadeOut(50); // Click to disappear immediately.
});
}
}
// load jQuery (if needed) and execute the main function
if(typeof jQuery == 'undefined') {
addJQuery(flickrSizeHackMain);
} else {
flickrSizeHackMain();
}