Flickr Cross-Recommendations

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

  1. // ==UserScript==
  2. // @name Flickr Cross-Recommendations
  3. // @namespace http://netcetera.org
  4. // @include http://www.flickr.com/photos/*
  5. // @include https://www.flickr.com/photos/*
  6. // @match http://www.flickr.com/photos/*
  7. // @match https://www.flickr.com/photos/*
  8. // @version 1.53f
  9. // @grant none
  10. // @author Simon Whitaker (http://www.flickr.com/people/chubbybat/)
  11. // @contributor Alesa Dam (http://www.flickr.com/people/alesadam/)
  12. // @contributor Darren Greaves (http://www.flickr.com/people/boncey/)
  13. // @contributor Martin Heimburger (http://www.flickr.com/people/Vispillo/)
  14. // @contributor Mark Boyd (https://www.flickr.com/people/mark_boyd/)
  15. // @description Adds a "People who faved this also faved..." panel to photos on Flickr
  16. // ==/UserScript==
  17.  
  18.  
  19. (function() {
  20. if (!document.location.href.match(/https?:\/\/www\.flickr\.com\/photos\/[^\/]+\/\d+.*/)) {
  21. return;
  22. }
  23. var MAX_IMGS = 6; // number of cross-recommendations to retrieve
  24. var MAX_RUNS = MAX_IMGS * 15; // if we don't have those random images by then, better quit
  25.  
  26. var current_element;
  27. var prev_element;
  28. var target_element;
  29. var current_photo_id;
  30. var photo_count;
  31. var run_count;
  32. var photos_to_ignore;
  33.  
  34. var testForElement = true;
  35. var pageURLCheckTimer = setInterval (
  36. function () {
  37. if ( this.lastPathStr !== location.pathname
  38. || this.lastQueryStr !== location.search
  39. || this.lastPathStr === null
  40. || this.lastQueryStr === null
  41. ) {
  42. this.lastPathStr = location.pathname;
  43. this.lastQueryStr = location.search;
  44. gmMain ();
  45. } else if (testForElement) {
  46. current_element = document.getElementsByClassName('view sub-photo-fave-view')[0];
  47. if (!current_element) {
  48. current_element = document.getElementsByClassName('fave-block')[0];
  49. }
  50. if (!current_element) {
  51. current_element = document.getElementById('comments');
  52. }
  53. if ((current_element != prev_element) && (current_element)) {
  54. prev_element = current_element;
  55. testForElement = false;
  56. FCR_add_panel(current_element);
  57. }
  58. }
  59. }
  60. , 200
  61. );
  62.  
  63. function gmMain () {
  64. if (!document.location.href.match(/https?:\/\/www\.flickr\.com\/.*/)) {
  65. clearInterval(pageURLCheckTimer);
  66. } else {
  67. testForElement = document.location.href.match(/https?:\/\/www\.flickr\.com\/photos\/[^\/]+\/\d+.*/);
  68. }
  69. }
  70. var protocol = window.location.protocol;
  71.  
  72. if (typeof(GM_log) == "undefined") { // Chrome
  73. GM_log = function(message) {
  74. console.info('FCR: ' + message);
  75. }
  76. }
  77.  
  78. var getJSVariable = function (regex) {
  79. // Thanks to Vispillo for this compact code
  80. var retval;
  81. var scripts = document.getElementsByTagName('script');
  82. for(var i = 0, len = scripts.length; i < len; ++i) {
  83. var script = scripts[i];
  84. var html = script.innerHTML;
  85. try {
  86. retval = regex.exec(html)[1];
  87. break;
  88. } catch (e) {
  89. }
  90. }
  91. return retval;
  92. }
  93. function pickRandomFavoriteFrom(people) {
  94. if (!people || people.length == 0) {
  95. GM_log("no people found");
  96. return;
  97. }
  98. if (photo_count >= MAX_IMGS) { // sanity check
  99. return;
  100. }
  101. if (++run_count > MAX_RUNS) {
  102. GM_log("out of data");
  103. return;
  104. }
  105. photos_to_ignore[current_photo_id] = 1;
  106. var personIdx = Math.floor(Math.random() * people.length);
  107. var nsid = people[personIdx].nsid;
  108. var listRequest = new XMLHttpRequest();
  109. listRequest.onload = function(getPublicListResponse) {
  110. var listJson = listRequest.response;
  111. try {
  112. var data = JSON.parse(listJson);
  113. } catch (e) {
  114. try {
  115. data = eval('(' + listJson + ')');
  116. } catch (f) {
  117. //GM_log("exception parsing list response: " + e);
  118. pickRandomFavoriteFrom(people);
  119. return;
  120. }
  121. }
  122. var photos = data.photos.photo;
  123. var photoIdx = Math.floor(Math.random() * photos.length);
  124. var photo = photos[photoIdx];
  125. if (typeof photo == 'undefined') {
  126. pickRandomFavoriteFrom(people);
  127. return;
  128. }
  129. if (photos_to_ignore[photo.id]) {
  130. pickRandomFavoriteFrom(people);
  131. return;
  132. }
  133. photos_to_ignore[photo.id] = 1;
  134. var photo_url = protocol + '//farm' + photo.farm
  135. + '.static.flickr.com/'
  136. + photo.server + '/'
  137. + photo.id + '_' + photo.secret + '_s.jpg';
  138. var page_url = protocol+'//www.flickr.com/photos/'
  139. + photo.owner
  140. + '/' + photo.id + '/';
  141. var img = document.createElement('img');
  142. img.setAttribute('src',photo_url);
  143. img.setAttribute('border', 0);
  144. var a = document.createElement('a');
  145. a.setAttribute('href', page_url);
  146. a.setAttribute('target', "_blank");
  147. a.setAttribute('title', photo.title);
  148. a.style.marginRight = '8px';
  149. a.appendChild(img);
  150. document.getElementById('FCR_photos').appendChild(a);
  151. // Show the main div, in case it's still hidden
  152. document.getElementById('FCR_main').style.display = "block";
  153. ++photo_count;
  154. pickRandomFavoriteFrom(people);
  155. };
  156. listRequest.open('get', protocol+'//api.flickr.com/services/rest/'
  157. +'?method=flickr.favorites.getPublicList'
  158. +'&api_key=' + api_key
  159. +'&format=json&nojsoncallback=1'
  160. +'&user_id=' + nsid,
  161. true);
  162. listRequest.send();
  163. }
  164.  
  165. function FCR_add_panel(the_element) {
  166. try {
  167. photo_count = 0;
  168. run_count = 0;
  169. photos_to_ignore = new Array();
  170. if (!the_element) {
  171. GM_log("element not found; aborting");
  172. return;
  173. }
  174. current_photo_id = re.exec(document.location.href)[1];
  175. var xrec_div = document.createElement('div');
  176. xrec_div.setAttribute('id', 'FCR_main');
  177. var xrec_photos = document.createElement('div');
  178. xrec_photos.setAttribute('id', 'FCR_photos');
  179. var xrec_header = document.createElement('h3');
  180. xrec_header.innerHTML = 'People who faved this also faved...';
  181. xrec_div.appendChild(xrec_header);
  182. xrec_div.appendChild(xrec_photos);
  183. the_element.parentNode.insertBefore(xrec_div, the_element);
  184.  
  185. xrec_div.style.display = 'none';
  186.  
  187. var url = protocol+'//api.flickr.com/services/rest/'
  188. +'?method=flickr.photos.getFavorites'
  189. +'&api_key=' + api_key
  190. +'&format=json&nojsoncallback=1'
  191. +'&photo_id=' + current_photo_id;
  192. var favesRequest = new XMLHttpRequest();
  193. favesRequest.onload = function(response) {
  194. var json = favesRequest.response;
  195. try {
  196. var data = JSON.parse(json);
  197. } catch (e) {
  198. try {
  199. data = eval('(' + json + ')');
  200. } catch (f) {
  201. GM_log("exception parsing response: " + e);
  202. return;
  203. }
  204. }
  205. pickRandomFavoriteFrom(data.photo.person);
  206. };
  207. favesRequest.open('get', url, true);
  208. favesRequest.send();
  209.  
  210. } catch (e) {
  211. GM_log("Exception occurred: " + e);
  212. }
  213. }
  214. var re = /flickr\.com\/photos\/[^\/]+\/(\d+).*/;
  215. var api_key = '45d5d4b7dff9bc653c8eb3e73271c10c';
  216.  
  217. })();