// ==UserScript== // @name Flickr AllSizes+ // @description Access all sizes for a Flickr photo. Copy the code, download the image, etc. // @author Premasagar Rose (http://premasagar.com/contact/) // @namespace http://premasagar.com // @identifier http://premasagar.com/dev/gm/flickrallsizesplus.user.js // @version 1.115 // @date 2007-01-23 // // @include http://www.flickr.com/photo_zoom.gne* // @include http://flickr.com/photo_zoom.gne* // @include http://www.flickr.com/photos/*/* // @include http://flickr.com/photos/*/* // // @exclude http://*flickr.com/photos/organize/* // @exclude http://*flickr.com/photos/friends/* // @exclude http://*flickr.com/photos/tags/* // // @exclude http://*flickr.com/photos/*/sets* // @exclude http://*flickr.com/photos/*/friends* // @exclude http://*flickr.com/photos/*/archives* // @exclude http://*flickr.com/photos/*/tags* // @exclude http://*flickr.com/photos/*/alltags* // @exclude http://*flickr.com/photos/*/multitags* // @exclude http://*flickr.com/photos/*/map* // @exclude http://*flickr.com/photos/*/favorites* // @exclude http://*flickr.com/photos/*/popular* // @exclude http://*flickr.com/photos/*/with* // ==/UserScript== /* INFO ==== Before installing this script, you'll need the Firefox browser (http://www.mozilla.org/firefox/) and the Greasemonkey extension (http://greasemonkey.mozdev.org) Discuss this script / report bugs / request features: http://www.flickr.com/groups/flickrhacks/discuss/72157594303798688/ Download the latest version: http://premasagar.com/dev/gm/flickrallsizesplus.user.js Released under the GPL license: http://www.gnu.org/copyleft/gpl.html SUMMARY ======= This script makes it easier to access all the sizes available for a photo, including the original size on non-Pro accounts. You can access the code for re-posting photos on Flickr discussion threads and other websites, as well as download images and more. To read the full documentation, click the "AllSizes" button on a photo's photopage and click on the 'Documentation' link. If you improve the script, please let me know... /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ (function() { // USERSCRIPT INFORMATION var UserScript = { id: 'flickrallsizesplus', title: 'Flickr AllSizes+', header: 'allSizes+', version: 1.115, date: new Date(2007, 0, 23), author: 'Premasagar', // Hours till next update check updateInterval: 24, // Api url to check for updates checkUpdateUrl: 'http://premasagar.com/api/checkupdates/', // Url for script discussion thread metaUrl: 'http://www.flickr.com/groups/flickrhacks/discuss/72157594303798688/', // Function to check for script updates checkForUpdates: function(){ // Does user want to check for updates? if (!Settings.getValue('checkforUpdates')) { return; } // Determine last time script was checked for updates var lastCheck = GM_getValue('lastUpdateCheck'); lastCheck = (typeof lastCheck != 'undefined') ? parseInt(lastCheck) : this.date.getTime(); // Get the current time var timeNow = new Date().getTime(); // Guard against weird stuff, like user changing system clock to the future if (lastCheck > timeNow) { lastCheck = timeNow; } // Is it time to check for updates? If not, return if (timeNow < (lastCheck + (this.updateInterval * 60 * 60 * 1000))) { return; } // Update the lastUpdateCheck local variable GM_setValue('lastUpdateCheck', timeNow.toString()); // +-+-+-+-+-+-+-+-+ // Api url for the update check var url = this.checkUpdateUrl + '?id=' + this.id + '&version=' + this.version + '&noCache=' + timeNow; var that = this; // Callback function for the AJAX request var callback = function(response){ // Bad response if (!response) { return; } else if (response.responseText == '') { return; } // Parse the response var parser = new DOMParser(); var dom = parser.parseFromString(response.responseText, "application/xml"); var rsp = dom.getElementsByTagName('rsp')[0]; // Our request failed! Return. if (rsp.getAttribute('stat') != 'ok') { return; } // Get userscript details var userscript = rsp.getElementsByTagName('userscript')[0]; var v = userscript.getAttribute('version'); var downloadUrl = userscript.getElementsByTagName('url')[0].textContent; var metaUrl = userscript.getElementsByTagName('url')[0].textContent; var changelog = userscript.getElementsByTagName('changelog')[0].textContent; // If there's no version update, then return if (v == that.version) { return; } // There's an update! Create a pop-up to tell the user var popUp = new PopUp('Update Available'); popUp.main.className = ''; var div = popUp.main.appendChild(cE('div')); div.className = 'indented'; var innerHTML = '
Script: ' + UserScript.title + '
'; innerHTML += 'Version ' + v + ' is now available.
'; innerHTML += ''; if (changelog != '') { innerHTML += '' + changelog + '
'; } div.innerHTML = innerHTML; popUp.open(); }; // Make the AJAX request ajaxRequest(url, callback); } }; // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // Check that latest version of Greasemonkey is installed if (!GM_xmlhttpRequest) { if (window.confirm('You do not have the latest version of Greasemonkey installed.\nWould you like to get it now?')) { window.location.href = 'http://greasemonkey.mozdev.org'; } return; } // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // Initialise script for essential functions initScript(); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // FLICKR REFERENCE OBJECT var Flickr = { // Urls imgRoot: 'http://static.flickr.com/', siteRoot: 'http://www.flickr.com/', // Flickr Regular Expressions regex: { photoSrc: /^(http:\/\/(farm\d{0,3}\.)?static\.flickr\.com\/(\d+)\/(\d+)_(\w+?)((_[stmb])?\.jpg|_o\.(jpg|gif|png))).*$/, photoPageUrl: /^((http:\/\/(www\.)?flickr\.com)?\/photos\/([\w@_-]+)\/(\d+))(\/.*)?$/, allSizesPageUrl: /^http:\/\/(www\.)?flickr\.com\/photo_zoom\.gne\?id=(\d+)&size=(sq?|[tmlo])$/, buddyiconSrc: /^(http:\/\/((farm\d{0,3}\.)?static.flickr.com\/(\d+)\/buddyicons\/([\w@_-]+)\.jpg(\?\d+)?|(www\.)?flickr\.com\/images\/buddyicon\.jpg\?([\w@_-]+)))$/, nsid: /^\d{8,12}@N\d{0,3}$/ } }; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // PHOTO OBJECT function Photo(id, secret, server){ this.id = id; this.secret = secret; this.server = server; this.init.init(this); } // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // STATIC FUNCTIONS ON PHOTO OBJECT Object.extend(Photo, { // Create Photo object from an image src fromSrc: function(src){ // Get parameters: id, secret, server, file extension for original size var params = src.replace(Flickr.regex.photoSrc, '$4,$5,$3,$8').split(","); // Create new Photo object var photo = new this(params[0], params[1], params[2]); // If the image is the original size, then set the original size file extension if (params[3] != '') { photo.sizes.o.extension = '.' + params[3]; } return photo; }, // Create Photo object from an image element fromImg: function(img){ // Create Photo object from the image src var photo = this.fromSrc(img.src); // Get the size suffix - e.g. '_s', '_t' var suffix = img.src.replace(Flickr.regex.photoSrc, '$6').slice(0,2); // For medium size if (suffix.slice(0,1) != '_') { suffix = ''; } // Determine which image size this is var size = $A(photo.sizes).getBy('suffix', suffix); if (size) { // Set the dimensions of this size and smaller sizes photo.sizes[size.id].setDimensions(img.width, img.height); photo.sizes.setDimensions(); } return photo; } }); // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // PHOTO OBJECT PROTOTYPE Photo.prototype = { // Init Object, for storing functions required at object initialisation init: new Init(), title: null, owner: null, // Get photo title. Add username to title, if user has requested it. getTitle: function(){ // Check title of page each time, in case owner/user changes it this.title = Page.getCurrentPage().getTitle(); // We don't yet know the title... if (!this.title) { return null; } // Replace blank titles with the user's setting for blank titles. var title = (this.title.length == 1 && this.title.charCodeAt(0) == 160) ? '' : this.title; if (title == '') { title = Settings.getValue('untitledTitle'); } // Check if we have the owner's username if (!this.owner) { return title; } if (!this.owner.username) { return title; } // Check the user's settings for adding the username to the title if ((this.isUser && Settings.getValue('addUsernameWhenYou')) || (!this.isUser && Settings.getValue('addUsernameToTitle')) ) { title += Settings.getValue('usernameFormat').replace(/\[user\]/g, this.owner.username); } // Convert any special characters to their HTML entities (e.g. &, <, ") return convertSpecialChars(title); }, // Get the url of the photopage for this photo getPhotopageUrl: function(){ // If we don't know the owner, then use the generic url if (!this.owner) { return Flickr.siteRoot + 'photo.gne?id=' + this.id; } // If we know the owner, then use the specific url else { return this.owner.getPhotosUrl() + this.id + '/'; } } }; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // PERSON OBJECT function Person(userUrl){ this.userUrl = userUrl; // Check if the userUrl is also the nsid if (userUrl.match(Flickr.regex.nsid)) { this.nsid = this.userUrl; } } // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // PERSON PROTOTYPE Person.prototype = { nsid: null, username: null, // Url for person's photostream getPhotosUrl: function(){ var userUrl = (this.userUrl) ? this.userUrl : this.nsid; return (userUrl) ? Flickr.siteRoot + 'photos/' + userUrl + '/' : null; }, // Url for person's profile getProfileUrl: function(){ var userUrl = (this.userUrl) ? this.userUrl : this.nsid; return (userUrl) ? Flickr.siteRoot + 'people/' + userUrl + '/' : null; }, // Url to send a FlickrMail getSendmailUrl: function(){ return (this.nsid) ? Flickr.siteRoot + 'messages_write.gne?to=' + this.nsid : null; } }; // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // STATIC FUNCTIONS ON PERSON OBJECT Object.extend(Person, { getNsidFromBuddyiconSrc: function(src){ var nsid = src.replace(Flickr.regex.buddyiconSrc, '$5'); if (nsid == '') { nsid = src.replace(Flickr.regex.buddyiconSrc, '$8'); } return (nsid != '') ? nsid : null; }, // Create a Person object by supplying the photopage url fromPhotopageUrl: function(url){ var userUrl = url.replace(Flickr.regex.photoPageUrl, '$4'); return new this(userUrl); }, // Create a Person object by supplying their buddyicon image src fromBuddyiconSrc: function(src){ var nsid = Person.getNsidFromBuddyiconSrc(src); if (!nsid) { return null; } var person = new this(nsid); person.nsid = nsid; return person; } }); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // PHOTO LICENCE OBJECT function License(id, name, url){ this.id = id; this.name = name; this.url = url; } // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // PHOTO LICENCE PROTOTYPE License.prototype = { // Get the icon to display for this license getIcon: function(){ if (this.id == 0) { return icon = cE('span', '\u00a9'); } // copyright symbol else if (this.id < Photo.licenses.length) { var icon = cE('img'); icon.src = EncodedImages.creativeCommonsIcon; return icon; } else { return null; } }, // Get an HTML anchor element to display the license icon and a link for further info getAnchor: function(){ var a = cE('a'); a.href = this.url; a.appendChild(this.getIcon()); a.appendChild(cTN(' ' + this.name)); return a; } }; // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // EXTEND PHOTO OBJECT WITH STATIC LICENSE OBJECTS // (not to Photo prototype, because a photo only has one license at a time) Object.extend(Photo, { licenses: [ new License(0, 'All Rights Reserved', 'http://www.iusmentis.com/copyright/allrightsreserved/'), new License(1, 'Attribution-NonCommercial-ShareAlike', 'http://creativecommons.org/licenses/by-nc-sa/2.0/'), new License(2, 'Attribution-NonCommercial', 'http://creativecommons.org/licenses/by-nc/2.0/'), new License(3, 'Attribution-NonCommercial-NoDerivs', 'http://creativecommons.org/licenses/by-nc-nd/2.0/'), new License(4, 'Attribution', 'http://creativecommons.org/licenses/by/2.0/'), new License(5, 'Attribution-ShareAlike', 'http://creativecommons.org/licenses/by-sa/2.0/'), new License(6, 'Attribution-NoDerivs', 'http://creativecommons.org/licenses/by-nd/2.0/') ] }); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // SIZE OBJECT function Size(initObj){ Object.extend(this, initObj); } // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // SIZE OBJECT PROTOTYPE Size.prototype = { extension:'.jpg', width: null, height: null, // Check if this size exists for this photo exists: function(){ // All sizes except large always exist if (this.id != 'l') { return true; } // LARGE SIZES // Get original size var o = this.photo.sizes.o; // If original has incomplete dimensions, check if large size has dimensions if (!o.width || !o.height) { return (this.width && this.height) ? true : null; } // Check original size dimensions return (o.width > 1280 || o.height > 1280) ? true : false; }, // Check if this size has a known image src isKnownSrc: function(){ return (this.exists() && this.extension) ? true : false; }, // Check if this size has known dimensions isKnownSize: function(){ return (this.width && this.height) ? true : false; }, // Check if this size has a known src and dimensions isComplete: function(){ // Check if original size rotation is known var knownRotation = true; if (typeof this.rotated != 'undefined') { knownRotation = (this.rotated !== null); } return (this.isKnownSrc() && this.isKnownSize() && knownRotation) ? true : false; }, // Get an array of the image dimensions getDimensions: function(){ return [this.width, this.height]; }, // Set the dimensions for this size // Optional args: width & height. If not supplied, size is calculated from larger sizes setDimensions: function(){ // If width and height are supplied... if (arguments.length > 0) { this.width = arguments[0]; if (arguments.length > 1) { this.height = arguments[1]; } return this.getDimensions(); } // If width & height not supplied... // Get the largest complete size, as a comparison var largest = this.photo.sizes.getLargestKnownSize(); if (!largest) { return false; } // If the largest size is this size, then return else if (largest.max == this.max) { return false; } // Check if the original was rotated by the owner if (largest.id == 'o' && this.photo.sizes.o.rotated) { // Copy object so that we can temporarily change its properties largest = Object.extend({}, largest); var temp = largest.width; largest.width = largest.height; largest.height = temp; } // If the largest size is smaller than this size if (largest.max < this.max) { // If the largest size is smaller than its max dimensions, then this has the same size if (largest.width < largest.max && largest.height < largest.max) { return this.setDimensions(largest.width, largest.height); } else { return false; } } // If this is the large size, then special rules apply else if (largest.id == 'o' && this.id == 'l' && largest.width <= 1280 && largest.height <= 1280) { return false; } // -- Calculate dimensions for this size // If the comparison size dimensions are no bigger than this size's maximum if (largest.width <= this.max && largest.height <= this.max) { return this.setDimensions(largest.width, largest.height); } // Else var longerSide = Math.max(largest.width, largest.height); var newWidth = Math.round(this.max * (largest.width/longerSide)); var newHeight = Math.round(this.max * (largest.height/longerSide)); return this.setDimensions(newWidth, newHeight); }, // Get the image src for this size // Optional arg: forDownload [boolean], default: false (returns src for the image download version) getSrc: function(){ // If essential info is not known, then return null if (!this.extension) { return null; } // Check forDownload flag if (arguments.length >0) { var suffix = (arguments[0]) ? this.suffix + '_d' : this.suffix; } else { var suffix = this.suffix; } return Flickr.imgRoot + this.photo.server + '/' + this.photo.id + '_' + this.photo.secret + suffix + this.extension; }, // Get an image element for this size getImg: function(){ // Get the image src var src = this.getSrc(); if (!src) { return null; } // Create a new image element and set attributes var img = Object.extend(cE('img'), { src: src, alt: this.photo.getTitle(), title: this.photo.getTitle() }); if (this.width) { img.width = this.width; } if (this.height) { img.height = this.height; } return img; }, // Get HTML tag for the image element getImgHTML: function(){ // Get the image src var src = this.getSrc(); if (!src) { return null; } // Get attributes for tag var width = (this.width) ? ' width="' + this.width + '"' : ''; var height = (this.height) ? ' height="' + this.height + '"' : ''; var title = ' title="' + this.photo.getTitle() + '"'; var alt = ' alt="' + this.photo.getTitle() + '"'; return '2. Grab the photo\'s URL:
'; html += ''; html += 'Remember! Flickr Terms of Service specify that if you post a Flickr photo on an external website, the photo must link back to its photo page. (So, use Option 1.)
'; // Create new node var newNode = cE('div'); newNode.innerHTML = html; // Add code to textarea var ta = newNode.getElementsByTagName('textarea')[0]; ta.value = this.getPhoto().sizes[this.getCurrentSize()].getCode(); // Insert into document elements[0].parentNode.insertBefore(newNode, elements[0]); return true; }, init: function(){ return this.updateTextarea(); } }, // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // Find the first page object that matches getCurrentPage: function(){ var pages = $A(this); for (var i=0; i| (size key) + Click | Code Pop-up |
| d + (size key) + Click | Download image |
| c + (size key) + Click | Copy code to clipboard |
| v + (size key) + Click | View image |
| (size key) + DoubleClick | All Sizes Page |