Flickr Cross-Recommendations

Adds a "People who faved this also faved..." panel to photos on Flickr

// ==UserScript==
// @name            Flickr Cross-Recommendations
// @namespace       http://netcetera.org
// @include         http://www.flickr.com/photos/*
// @include         https://www.flickr.com/photos/*
// @match           http://www.flickr.com/photos/*
// @match           https://www.flickr.com/photos/*
// @version         1.53f
// @grant           none
// @author          Simon Whitaker (http://www.flickr.com/people/chubbybat/)
// @contributor     Alesa Dam (http://www.flickr.com/people/alesadam/)
// @contributor     Darren Greaves (http://www.flickr.com/people/boncey/)
// @contributor     Martin Heimburger (http://www.flickr.com/people/Vispillo/)
// @contributor     Mark Boyd (https://www.flickr.com/people/mark_boyd/)
// @description     Adds a "People who faved this also faved..." panel to photos on Flickr
// ==/UserScript==


(function() {
if (!document.location.href.match(/https?:\/\/www\.flickr\.com\/photos\/[^\/]+\/\d+.*/)) {
	return;
}
    
var MAX_IMGS = 6;             // number of cross-recommendations to retrieve
var MAX_RUNS = MAX_IMGS * 15; // if we don't have those random images by then, better quit

var current_element;
var prev_element;
var target_element;
var current_photo_id;
    
var photo_count;
var run_count;
var photos_to_ignore;

var testForElement = true;
    
var pageURLCheckTimer = setInterval (
    function () {
        if (    this.lastPathStr  !== location.pathname
            ||  this.lastQueryStr !== location.search
            ||  this.lastPathStr   === null
            ||  this.lastQueryStr  === null
        ) {
            this.lastPathStr  = location.pathname;
            this.lastQueryStr = location.search;
            gmMain ();
        } else if (testForElement) {
           current_element = document.getElementsByClassName('view sub-photo-fave-view')[0];
           if (!current_element) {
               current_element = document.getElementsByClassName('fave-block')[0];
           }
           if (!current_element) {
               current_element = document.getElementById('comments');
           }
           if ((current_element != prev_element) && (current_element)) {
               prev_element = current_element;
               testForElement = false;
							 FCR_add_panel(current_element); 
           }
        }
    }
    , 200
);

function gmMain () {
    if (!document.location.href.match(/https?:\/\/www\.flickr\.com\/.*/)) {
				clearInterval(pageURLCheckTimer);
    } else {
				testForElement = document.location.href.match(/https?:\/\/www\.flickr\.com\/photos\/[^\/]+\/\d+.*/);
		}
}
    
var protocol = window.location.protocol;

if (typeof(GM_log) == "undefined") { // Chrome
	GM_log = function(message) {
		console.info('FCR: ' + message);
	}
}

var getJSVariable = function (regex) {
        // Thanks to Vispillo for this compact code
        var retval;
        var scripts = document.getElementsByTagName('script');
	for(var i = 0, len = scripts.length; i < len; ++i) {
	    var script = scripts[i];
            var html = script.innerHTML;
            try {
                retval = regex.exec(html)[1];
		break;
            } catch (e) {
            }
        }
        return retval;
}
    
function pickRandomFavoriteFrom(people) {
	if (!people || people.length == 0) {
		GM_log("no people found");
		return;
	}
	if (photo_count >= MAX_IMGS) { // sanity check
		return;
	}
	if (++run_count > MAX_RUNS) {
GM_log("out of data");
		return;
	}
	photos_to_ignore[current_photo_id] = 1;
	
	var personIdx = Math.floor(Math.random() * people.length);
	var nsid = people[personIdx].nsid;
	    
	var listRequest = new XMLHttpRequest();
	listRequest.onload = function(getPublicListResponse) {
		    var listJson = listRequest.response;
		    try {
			var data = JSON.parse(listJson);
		    } catch (e) {
			try {
				data   = eval('(' + listJson + ')');
			} catch (f) {
				//GM_log("exception parsing list response: " + e);
				pickRandomFavoriteFrom(people);
				return;
			}
		    }
		    var photos = data.photos.photo;
		    
		    var photoIdx = Math.floor(Math.random() * photos.length);
		    var photo  = photos[photoIdx];
            if (typeof photo == 'undefined') {
			    pickRandomFavoriteFrom(people);
                return;
            }
		    if (photos_to_ignore[photo.id]) {
			    pickRandomFavoriteFrom(people);
			    return;
		    }
		    photos_to_ignore[photo.id] = 1;
		    
			var photo_url = protocol + '//farm' + photo.farm
				      + '.static.flickr.com/' 
				      + photo.server + '/' 
				      + photo.id + '_' + photo.secret + '_s.jpg';
		    
			var page_url  = protocol+'//www.flickr.com/photos/'
				      + photo.owner
				      + '/' + photo.id + '/';
						
			var img = document.createElement('img');
			img.setAttribute('src',photo_url);
			img.setAttribute('border', 0);
		    
			var a = document.createElement('a');
			a.setAttribute('href', page_url);
            a.setAttribute('target', "_blank");
			a.setAttribute('title', photo.title);
			a.style.marginRight = '8px';
			a.appendChild(img);
		    
			document.getElementById('FCR_photos').appendChild(a);
		    
			// Show the main div, in case it's still hidden
			document.getElementById('FCR_main').style.display = "block";
		    
			++photo_count;
			pickRandomFavoriteFrom(people);
		};
	listRequest.open('get', protocol+'//api.flickr.com/services/rest/'
		       +'?method=flickr.favorites.getPublicList'
		       +'&api_key=' + api_key
		       +'&format=json&nojsoncallback=1'
		       +'&user_id=' + nsid,
		true);
	listRequest.send();
}

function FCR_add_panel(the_element) {
try {
    photo_count = 0;
    run_count = 0;
    photos_to_ignore = new Array();    
    if (!the_element) {
	   GM_log("element not found; aborting");
	   return;
    }
    current_photo_id = re.exec(document.location.href)[1];
    var xrec_div     = document.createElement('div');
    xrec_div.setAttribute('id', 'FCR_main');
    var xrec_photos  = document.createElement('div');
    xrec_photos.setAttribute('id', 'FCR_photos');
    var xrec_header  = document.createElement('h3');
    xrec_header.innerHTML = 'People who faved this also faved...';
    
    xrec_div.appendChild(xrec_header);
    xrec_div.appendChild(xrec_photos);
    the_element.parentNode.insertBefore(xrec_div, the_element);

    xrec_div.style.display = 'none';

    var url =  protocol+'//api.flickr.com/services/rest/'
               +'?method=flickr.photos.getFavorites'
               +'&api_key=' + api_key
               +'&format=json&nojsoncallback=1'
               +'&photo_id=' + current_photo_id;
    
  
    var favesRequest = new XMLHttpRequest();
    favesRequest.onload = function(response) {
	    var json = favesRequest.response;
	    try {
		var data = JSON.parse(json);
	    } catch (e) {
		try {
			data = eval('(' + json + ')');
		} catch (f) {
			GM_log("exception parsing response: " + e);
			return;
		}
	    }
            pickRandomFavoriteFrom(data.photo.person);
            
        };
    favesRequest.open('get', url, true);
    favesRequest.send();

} catch (e) {
    GM_log("Exception occurred: " + e);
}
}
 
    var re = /flickr\.com\/photos\/[^\/]+\/(\d+).*/;
    var api_key = '45d5d4b7dff9bc653c8eb3e73271c10c';

})();