2 // @name Flickr Virtual Sets
4 // @description Adding virtual sets to photo pages
5 // @namespace http://webdev.yuan.cc/
6 // @include http://flickr.com/*
7 // @include http://www.flickr.com/*
9 // Author: .CK ( http://www.flickr.com/photos/ckyuan/ )
10 // Web site: http://webdev.yuan.cc/
12 // v1.0 06/27/06 initial release
13 // v1.1 06/30/06 Add "Your Favorites he/she owns" and "Your
15 // v1.2 07/01/06 Mortimer? (Pierre Andrews) contributes "User most
16 // interesting" and "Your most interesting"
17 // v1.3 07/01/06 Mortimer? (Pierre Andrews) contributes "Your photos
18 // in that pool" and "This user's photos in that pool"
19 // v2.0 07/12/06 Add virtual sets in "SET" page
20 // allow users to add photos in virtual sets to a real set
21 // v2.1 08/27/06 Mortimer? (Pierre Andrews) contributes "Relevant Photos"
23 // A Virtual Set is not a real photoset in Flickr. It's a set of photos
24 // sharing common properties or "things", say, your favorites, same tags,
25 // or same privacy settings. This script builds a navigating photostream
26 // box for each pre-defined virtual set. When you surfing photo pages,
27 // if a photo is in any of the virtual sets, the photostream box(es) will
28 // be opened automatically.
30 // In the "You" menu, this script will insert a link - "Your Virtual Sets"
31 // to let you choose which virtual sets you want to enable. The preference
32 // is stored in your Firefox. Now we have 6 pre-defined virtual sets:
34 // 1. Your Favorites - a collection of favorite photos
35 // 2. Recent Photos of Contacts - recent uploaded photos of your contacts,
37 // 3. Your Private Photos - all your private photos (not for friends and family)
38 // 4. Today Interesting - 500 interesting photos on uploaded day
39 // 5. Geotagged Photos - photos with "tag: geotagged" of the current user
40 // 6. Friends Only - photos only visible to friends of current user
41 // 7. Your Favorites owned by xxx - your favorites owned by current user
42 // 8. Your Favorited Photos - your photos favorited by others
43 // 9. User Most Interesting - most interesting photos of current user
44 // 10. Your Most Interesting - most interesting photos of you
45 // 11. Your photos in that pool
46 // 12. This user's photos in that pool
48 // In the "Photo Sets" page, either yours or others, the virtual sets will be
49 // inserted. Click any of the virtual sets, a floating div will pop up to show
50 // the photo thumbs in that set. If it the virtual set belongs to you, you can
51 // add them to a real set, either a new created one or an existing one.
58 if(DEBUG) GM_log('Starting GM Flickr Virtual Sets');
60 if(unsafeWindow) w = unsafeWindow;
62 var global_photos = w.global_photos;
63 var global_nsid = w.global_nsid;
65 function _gt(e) { return document.getElementsByTagName(e); }
66 function _gi(e) { return document.getElementById(e); }
67 function _ce(e) { return document.createElement(e); }
68 function _ct(e) { return document.createTextNode(e); }
70 var photo_id,ownersUrl,nsid,widget,posted,posted2;
71 var _fwd=false, _bwd=false;
72 var vsets = new Array();
73 var headers = { 'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey/Flickr Favorites Photostream', 'Accept': 'application/atom+xml,application/xml,text/xml' };
74 var context_loading = 'data:image/gif;base64,R0lGODlhSwBLAIAAAPPz8wAAACH5BAAAAAAALAAAAABLAEsAAAKDhI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC8fyTNf2jef6zvf+DwwKh8Si8YhMUgIVJsB5g0qkOGhAerVeDc4swsvqchPi59iMLq/KWvbZjV6/52k6XM5tt+0H8P2nlrSlRFhoeIiYqLjI2Oj4CBkpOUlZaXmJmam5ydnp+QnaUQAAOw==';
75 // var context_loading = 'http://www.flickr.com/images/context_loading.gif';
76 w.showSet = new Array();
77 w.addtoSet = new Array();
80 title: 'Your Favorites',
81 slide: 'http://www.flickr.com/photos/' +global_nsid+ '/favorites/show/',
82 browse: 'http://www.flickr.com/photos/' +global_nsid+ '/favorites/',
88 method: 'flickr.favorites.getList',
97 title: 'Recent Contacts Photos',
98 slide: 'http://www.flickr.com/photos/friends/show/',
99 browse: 'http://www.flickr.com/photos/friends/',
105 method: 'flickr.photos.getContactsPhotos',
113 // for(var i in d) if(d[i].className == 'Widget') widget = d[i];
114 for(var i=0;i<d.length;i++) {
115 if(d[i].className == 'Widget') {
121 posted = widget.getElementsByTagName('a')[1].href;
122 alias = widget.getElementsByTagName('a')[2].firstChild.innerHTML;
123 posted = posted.replace( /^.*date-posted\// , '');
125 posted = posted.replace( /\//g , '-');
126 posted = posted.replace( /-$/ , '');
127 nsid = widget.getElementsByTagName('img')[0].src;
128 nsid = nsid.replace( /^.*buddyicons\//, '');
129 nsid = nsid.replace( /\.jpg.*$/, '');
131 var t = _gi('SubNav');
133 nsid = t.getElementsByTagName('img')[0].src;
134 nsid = nsid.replace( /^.*buddyicons\//, '');
135 nsid = nsid.replace( /\.jpg.*$/, '');
136 if( nsid == global_nsid ) isOwner = true;
137 else isOwner = false;
140 var interestingness = {
141 title: 'Today Interesting',
142 slide: 'http://www.flickr.com/explore/',
143 browse: 'http://www.flickr.com/explore/interesting/'+ posted2,
149 method: 'flickr.interestingness.getList',
157 //var nsid = w.nextprev_currentContextID.replace(/stream/,'');
159 title: 'Geotagged Photos',
160 slide: 'http://www.flickr.com/photos/' +nsid+ '/tags/geotagged/show/',
161 browse: 'http://www.flickr.com/photos/' +nsid+ '/tags/geotagged/',
167 method: 'flickr.photos.search',
177 title: 'Friends Only',
178 slide: 'http://www.flickr.com/photos/' +nsid+ '/',
179 browse: 'http://www.flickr.com/photos/' +nsid+ '/',
185 method: 'flickr.photos.search',
198 title: 'Your Private Photos',
199 slide: 'http://www.flickr.com/photos/' +global_nsid+'/',
200 browse: 'http://www.flickr.com/photos/' +global_nsid+ '/',
206 method: 'flickr.photos.search',
207 user_id: global_nsid,
216 title: 'Your Favs Owned by User',
217 slide: 'http://www.flickr.com/photos/' +global_nsid+ '/favorites/show/',
218 browse: 'http://www.flickr.com/photos/' +global_nsid+ '/favorites/',
224 method: 'flickr.favorites.getList',
236 title: 'Your Favorited Photos',
238 browse: 'http://www.flickr.com/photos/' +global_nsid+ '/popular-faves/',
249 var userinteresting = {
250 title: 'This User Most Interesting',
252 browse: 'http://interestingby.isaias.com.mx/pm.php?id='+nsid+'&theme=white',
258 method: 'flickr.photos.search',
262 sort: 'interestingness-desc'
268 var yourinteresting = {
269 title: 'Your Most Interesting',
271 browse: 'http://www.flickr.com/photos/'+global_nsid+'/popular-interesting/',
277 method: 'flickr.photos.search',
280 user_id: global_nsid,
281 sort: 'interestingness-desc'
287 var group_name = /\/in\/pool-([^\/]+)/.exec(document.location.pathname);
289 group_name = group_name[1];
290 group_id = w.nextprev_currentContextID.replace(/pool/,'');
295 var yourphotoinpool = {
296 title: 'Your Photos in that pool',
298 browse: 'http://www.flickr.com/groups/'+group_name+'/pool/'+global_nsid+'/',
299 group_name: group_name,
305 method: 'flickr.groups.pools.getPhotos',
316 title: 'This user\'s photos in that pool',
318 browse: 'http://www.flickr.com/groups/'+group_name+'/pool/'+nsid+'/',
319 group_name: group_name,
325 method: 'flickr.groups.pools.getPhotos',
335 var re = /http:\/\/(www\.)?flickr\.com\/photos\/[^\/]+\/\d+/;
336 var re2 = /http:\/\/(www\.)?flickr\.com\/photos\/[^\/]+\/sets\/$/;
337 var re3 = /http:\/\/(www\.)?flickr\.com\/photos\/[^\/]+\/sets\/\d+\//;
338 if( re.test(document.location) || re3.test(document.location) ) {
340 for(tag in w.global_photos[w.page_photo_id].tags_rawA) {
341 tag_value = w.global_photos[w.page_photo_id].tags_rawA[tag];
342 if(tag_value.indexOf('geo:')<0) tags += ','+ tag_value;
344 tags = tags.substr(1);
345 GM_log('Tags: ' + tags);
348 var relevantphotos = {
349 title: 'Relevant Photos',
351 browse: 'http://flickr.com/search/?q='+tags+'&m=tags&z=t',
357 method: 'flickr.photos.search',
367 vsets['vset1'] = { enabled: function() { return GM_getValue('vset1',false); }, config: favorites };
368 vsets['vset2'] = { enabled: function() { return GM_getValue('vset2',false); }, config: contacts };
369 vsets['vset3'] = { enabled: function() { return GM_getValue('vset3',false); }, config: private };
370 vsets['vset4'] = { enabled: function() { return GM_getValue('vset4',false); }, config: interestingness };
371 vsets['vset5'] = { enabled: function() { return GM_getValue('vset5',false); }, config: geotagged };
372 vsets['vset6'] = { enabled: function() { return GM_getValue('vset6',false); }, config: friends };
373 vsets['vset7'] = { enabled: function() { return GM_getValue('vset7',false); }, config: favorites2 };
374 vsets['vset8'] = { enabled: function() { return GM_getValue('vset8',false); }, config: favorited };
375 vsets['vset9'] = { enabled: function() { return GM_getValue('vset9',false); }, config: userinteresting };
376 vsets['vset10'] = { enabled: function() { return GM_getValue('vset10',false); }, config: yourinteresting };
377 vsets['vset11'] = { enabled: function() { return GM_getValue('vset11',false); }, config: yourphotoinpool };
378 vsets['vset12'] = { enabled: function() { return GM_getValue('vset12',false); }, config: photoinpool };
379 vsets['vset13'] = { enabled: function() { return GM_getValue('vset13',false); }, config: relevantphotos };
382 function addCandyMenu() {
384 if(DEBUG) GM_log('Call addCandyMenu()');
387 var links = _gi('candy_nav_menu_you').getElementsByTagName('a');
388 for(var i=0;i<links.length;i++)
389 if(links[i].innerHTML=='Your Sets') your_sets = links[i];
391 if(DEBUG && your_sets) GM_log(your_sets.innerHTML);
393 var your_virtualsets = _ce('a');
394 your_virtualsets.title = 'Your virtual sets';
395 your_virtualsets.innerHTML = 'Your Virtual Sets';
396 your_virtualsets.href = 'javascript:;';
397 your_virtualsets.addEventListener('click', function() {
398 if( ! _gi('vset_menu') ) {
399 var vset_menu = _ce('div');
400 vset_menu.id = 'vset_menu';
401 vset_menu.style.position = 'absolute';
402 vset_menu.style.textAlign = 'left';
403 vset_menu.style.zIndex = 6000;
404 vset_menu.style.padding = '0px 10px 10px 10px';
405 vset_menu.style.margin = '60px 0px 0px 120px';
406 vset_menu.style.border = '1px solid #000';
407 vset_menu.style.color = '#4358c6';
408 vset_menu.style.font = '11px tahoma';
409 vset_menu.style.background = '#dfefff';
411 vset_menu.innerHTML = '<h4>Virtual Sets Settings</h4>';
413 vset_menu.innerHTML += '<input id="' +v+ '" type="checkbox"> ' +vsets[v].config.title+ '<br />';
414 vset_menu.innerHTML += '<input id="vset_save" type="button" class="Butt" value="Save"> ';
415 vset_menu.innerHTML += '<input id="vset_cancel" type="button" class="Butt" value="Cancel">';
417 _gi('Main').insertBefore(vset_menu, _gi('Main').firstChild);
418 _gi('vset_save').addEventListener('click', function() {
419 _gi('vset_menu').style.display = 'none';
420 for(var v in vsets) GM_setValue(v, _gi(v).checked);
423 _gi('vset_cancel').addEventListener('click', function() {
424 _gi('vset_menu').style.display = 'none';
426 } else vset_menu = _gi('vset_menu');
427 _gi('vset_menu').style.display = 'block';
428 for(var v in vsets) _gi(v).checked = (GM_getValue(v,false)=='1') ? true : false;
430 your_sets.parentNode.insertBefore(your_virtualsets, your_sets.nextSibling);
432 var your_popular = _ce('a');
433 your_popular.title = 'Your popular photos';
434 your_popular.innerHTML = 'Your Popular';
435 your_popular.href = your_sets.href.replace( /\/sets\//, '/popular-interesting/');
436 your_sets.parentNode.insertBefore(your_popular, your_virtualsets.nextSibling);
441 var re = /http:\/\/(www\.)?flickr\.com\/photos\/[^\/]+\/\d+/;
442 var re2 = /http:\/\/(www\.)?flickr\.com\/photos\/[^\/]+\/sets\/$/;
443 var re3 = /http:\/\/(www\.)?flickr\.com\/photos\/[^\/]+\/sets\/\d+\//;
444 if( ! re.test(document.location) && ! (re2.test(document.location) || !re3.test(document.location))) return;
446 for(var i in global_photos) photo_id = global_photos[i].id;
448 var ownersUrl = global_photos[photo_id].ownersUrl;
449 var isPublic = global_photos[photo_id].isPublic;
450 var isOwner = global_photos[photo_id].isOwner;
453 function sign(params) {
455 params.api_key = w.global_magisterLudi;
456 params.auth_hash = w.global_auth_hash;
457 params.auth_token = w.global_auth_token;
460 for(var p in params) {
463 _12+="&"+p+"="+w.escape_utf8(params[p]);
466 var cal=w.global_flickr_secret;
468 for(var i=0;i<_11.length;i++) cal+=_11[i]+params[_11[i]];
469 cal=w.md5_calcMD5(cal);
470 _12="api_sig="+cal+_12;
475 function searchPhoto(params,callback,list,paged,filters) {
477 if(DEBUG) GM_log('Call searchPhoto()');
482 var callAPI = function(url) {
484 if(DEBUG) { GM_log(url); }
486 method: 'GET', url: url, headers: headers,
487 onload: function(responseDetails) {
488 // if(DEBUG) GM_log(responseDetails.responseText);
489 var parser = new w.DOMParser();
490 var dom = parser.parseFromString(responseDetails.responseText, "application/xml");
491 var stat = dom.getElementsByTagName('rsp')[0].getAttribute('stat');
493 var pages = dom.getElementsByTagName('photos')[0].getAttribute('pages');
494 var page = dom.getElementsByTagName('photos')[0].getAttribute('page');
495 var total = dom.getElementsByTagName('photos')[0].getAttribute('total');
496 var photos = dom.getElementsByTagName('photo');
497 for(var i=0;i<photos.length;i++) {
499 for(var j in filters) if( photos[i].getAttribute(j) != filters[j] ) skip = true;
501 var index = list.length;
502 list[index] = new Object();
503 list[index].id = photos[i].getAttribute('id');
504 list[index].owner = photos[i].getAttribute('owner');
505 list[index].secret = photos[i].getAttribute('secret');
506 list[index].server = photos[i].getAttribute('server');
507 list[index].img_s = 'http://static.flickr.com/'+list[index].server+'/'+list[index].id+'_'+list[index].secret+'_s.jpg';
508 list[index].img_m = 'http://static.flickr.com/'+list[index].server+'/'+list[index].id+'_'+list[index].secret+'_m.jpg';
509 list[index].url = 'http://www.flickr.com/photos/' + list[index].owner + '/'+ list[index].id +'/';
510 if( photo_id == list[index].id ) _index = index+1;
512 if( paged && pages>page ) {
514 url = 'http://www.flickr.com/services/rest/?' + sign(params);
516 } else callback(_index,list,total);
517 } else callback(-1, new Array(),0);
521 var url = 'http://www.flickr.com/services/rest/?' + sign(params);
525 function searchFaved(params,callback,favs,paged,filters) {
527 var url = 'http://www.flickr.com/photos/' +global_nsid+ '/popular-faves/';
528 var _index=-1, total=0;
530 function callHTML(url,page) {
531 url1 = url + 'page' + page +'/';
532 if(DEBUG) GM_log(url1);
537 onload: function(responseDetails) {
538 if(DEBUG) GM_log('Faved page' +page+ ' loaded');
540 var html = ''+responseDetails.responseText;
541 var rExp = /[\r\t\n\f]/g;
542 html = html.replace(rExp, '');
545 rExp = /<div class="Results">\((\d+) photos\)<\/div>/;
546 var r = rExp.exec(html);
548 favs[total-1] = new Object();
550 rExp = /(http:\/\/static.flickr.com\/\d+\/\d+_\w+_s\.jpg)/;
551 var imgExp = /http:\/\/static.flickr.com\/(\d+)\/(\d+)_(\w+)_s\.jpg/;
552 while( rExp.test(html) ) {
553 var m = rExp.exec(html);
554 var n = imgExp.exec(m[1]);
555 html = html.replace(rExp,'');
557 favs[i] = new Object();
559 favs[i].owner = global_nsid;
560 favs[i].secret = n[3];
561 favs[i].server = n[1];
562 favs[i].img_s = m[1];
563 favs[i].img_m = 'http://static.flickr.com/'+favs[i].server+'/'+favs[i].id+'_'+favs[i].secret+'_m.jpg';
564 favs[i].url = 'http://www.flickr.com/photos/' + favs[i].owner + '/'+ favs[i].id +'/';
565 if( photo_id == favs[i].id ) _index = i+1;
568 // if( page < (total-total%20)/20+1 ) callHTML(url,page+1);
569 // else callback(_index,favs);
570 if( paged && page==1 ) {
571 for(var j=2; j<= (total-total%20)/20+1; j++) callHTML(url,j);
576 callback(_i,favs,total,false);
577 } else callback(-1,favs,total,true);
584 function checkCache(id,key) {
586 var timestamp = 1*GM_getValue(id + '_time', '0');
587 var now = new Date();
588 if(DEBUG) GM_log(now.getTime() + ', ' + timestamp);
589 if( now.getTime() - timestamp > 2*60*60*1000 ) {
590 if(DEBUG) GM_log('Cache expired');
593 if(DEBUG) GM_log('Cache valid');
594 var str = GM_getValue(id, '');
595 var pairs = str.split(':');
596 if( pairs[0]!=key ) return true;
598 var items = pairs[1].split(',');
599 for(var i=0; i<items.length; i++)
600 if( items[i] == photo_id ) return true;
605 function Photostream(config) {
607 if(DEBUG) GM_log('Load ' + config.title );
609 var index, box, _fwd, _bwd;
610 var arrow_next, arrow_prev, div, box, browse_link, thumb_prev, thumb_next;
613 this.photos = new Array();
614 this.config = config;
617 var id = config.title.replace(/ /g, '_');
619 for(var i in config) {
620 if( typeof(config[i]) == 'object' ) for(var j in config[i]) key += j+config[i][j];
621 else key += i+config[i];
623 key = w.md5_calcMD5(key);
624 if( config.cache && !checkCache(id, key) ) return;
625 if(DEBUG) GM_log('Cache miss');
627 var insertPoint = _gi('other_contexts_p');
628 var load_vset = _ce('div');
629 load_vset.style.border = '1px solid #e3e3e3';
630 load_vset.style.background = '#f3f3f3';
631 load_vset.style.padding = '4px';
632 load_vset.innerHTML = '<img src="http://www.flickr.com/images/pulser2.gif" /> Loading ' + config.title;
633 if( insertPoint.nextSibling )
634 insertPoint.parentNode.insertBefore(load_vset,insertPoint.nextSibling);
635 else insertPoint.parentNode.appendChild(load_vset);
637 var move = function(photos,index) {
638 if( _fwd || _bwd ) { p = index-1; q = index; }
639 else { p = index-2; q = index; }
640 _fwd = false; _bwd = false;
643 thumb_prev.src = context_loading;
644 thumb_prev.src = photos[p].img_s;
645 thumb_prev.parentNode.href = photos[p].url + ( (config.group_name) ? 'in/pool-'+config.group_name: '') +'/';
647 thumb_prev.src = 'http://www.flickr.com/images/placeholder_first_photo.gif';
648 thumb_prev.parentNode.href = '#';
650 if(q<=photos.length-1) {
651 thumb_next.src = context_loading;
652 thumb_next.src = photos[q].img_s;
653 thumb_next.parentNode.href = photos[q].url + ( (config.group_name) ? 'in/pool-'+config.group_name: '') +'/';
655 thumb_next.src = 'http://www.flickr.com/images/placeholder_last_photo.gif';
656 thumb_next.parentNode.href = '#';
658 page = (index-index%config.perpage)/config.perpage + 1;
659 browse_link.href = config.browse + ((config.paged) ? ('page'+page+'/') : '');
662 var callback = function(index,photos,total,wait) {
664 for(var i=0;i<photos.length;i++) {
665 if(photos[i]) str += photos[i].id +',';
667 var now = new Date();
669 GM_setValue(id+'_time', '' + now.getTime());
671 if( config.addself && index==-1 ) index=0;
673 if( !wait ) insertPoint.parentNode.removeChild(load_vset);
677 var page = (index-index%config.perpage)/config.perpage + 1;
678 var divs = _gt('div');
679 for(var i=0;i<divs.length; i++) {
680 if( divs[i].className == 'ContextTop' ) {
685 // var _bb = w.document.getElementById('nextprev_button_'+w.nextprev_currentContextID);
686 if( ! w.nextprev_currentContextID.match(/stream.*/) ) ps = _gi('contextDiv_'+w.nextprev_currentContextID);
688 div = ps.cloneNode(true);
689 div.id = 'fav_stream';
690 insertPoint.style.display = 'block';
692 var trs = div.getElementsByTagName('tr');
693 for(var i=0;i<trs.length;i++) trs[i].id = '';
694 trs[1].style.display = 'table-row';
695 trs[1].id = 'favorites';
698 var imgs = div.getElementsByTagName('img');
699 for(var i=0;i<imgs.length;i++) {
700 if( imgs[i].className == 'nextprev_button' ) var t_np = imgs[i];
701 if( imgs[i].className == 'nextprev_arrows_img_next' ) {
702 arrow_next = imgs[i];
703 arrow_next.style.visibility = 'visible';
704 arrow_next.addEventListener('click', function() {
706 if( index > photos.length ) index = photos.length;
711 if( imgs[i].className == 'nextprev_arrows_img_prev' ) {
712 arrow_prev = imgs[i];
713 arrow_prev.style.visibility = 'visible';
714 arrow_prev.addEventListener('click', function() {
716 if( index < 0 ) index = 0;
723 var tbox_open = true;
724 t_np.src = 'http://www.flickr.com/images/context_open.gif';
725 t_np.onclickHandler = function() {
727 box.style.display = 'none';
728 this.src = 'http://www.flickr.com/images/context_closed.gif';
730 box.style.display = 'table-row';
731 this.src = 'http://www.flickr.com/images/context_open.gif';
733 tbox_open = !tbox_open;
735 t_np.addEventListener('click', t_np.onclickHandler, true);
737 load_vset.parentNode.replaceChild(div, load_vset);
739 var elms = div.getElementsByTagName('a');
740 for(var i=0; i<elms.length; i++) {
741 // if( elms[i].className == 'currentContextLink' || elms[i].className == 'Grey' ) {
742 if( elms[i].className == 'currentContextLink' ) {
743 elms[i].href = config.browse;
744 elms[i].innerHTML = config.title + ' <br />(Virtual Set)';
746 if( elms[i].className == 'contextThumbLink' ) {
747 browse_link = elms[i];
748 browse_link.href = config.browse + ((config.paged) ? ('page'+page+'/') : '');
752 var divs = div.getElementsByTagName('div');
753 for(var i=0; i<divs.length; i++) {
754 if(divs[i].className == 'nextprev_contextThumbsDiv') var target = divs[i];
755 if(divs[i].className == 'photosNum') divs[i].innerHTML = photos.length;
756 if(divs[i].className == 'showLink') {
757 if( config.slide=='' ) divs[i].style.display = 'none';
758 else divs[i].getElementsByTagName('a')[0].href = config.slide;
761 var imgs = target.getElementsByTagName('img');
762 thumb_prev = imgs[0];
763 thumb_next = imgs[1];
764 thumb_prev.src = context_loading;
765 thumb_next.src = context_loading;
769 if(!config.funct) var stream = new searchPhoto(config.params,callback, this.photos, config.api_paged, config.filters);
770 else var stream = new config.funct(config.params,callback, this.photos, config.api_paged, config.filters);
773 function VirtualSet(config) {
775 if(DEBUG) GM_log('Load ' + config.title );
777 var index, box, _fwd, _bwd;
778 var arrow_next, arrow_prev, div, box, browse_link, thumb_prev, thumb_next;
781 this.config = config;
782 this.photos = new Array();
785 var id = config.title.replace(/ /g, '_');
787 for(var i in config) {
788 if( typeof(config[i]) == 'object' ) for(var j in config[i]) key += j+config[i][j];
789 else key += i+config[i];
791 key = w.md5_calcMD5(key);
792 // if( config.cache && !checkCache(id, key) ) return;
793 if(DEBUG) GM_log('Cache miss');
795 var insertPoint = _gi('SubNav');
796 var load_vset = _ce('div');
797 load_vset.className = 'Sets';
798 load_vset.innerHTML = '<div class="SetCase"><div class="setLinkDiv"><a id="vsetlink_' +id+ '" href="#" class="setLink"><img id="vsethumb_' +id+ '" src="'+context_loading+'" class="setThumb"></a></div></div>';
799 load_vset.innerHTML += '<h4><a id="vsetlink2_' +id+ '" href="#" class="Seta">' +config.title+ '</a></h4>';
800 load_vset.innerHTML += '<p style="color:#ff0084"><b id="vsetnum_'+id+'"></b> photos<br /><i>in this Virtual Set</i></p>';
801 if( insertPoint.nextSibling )
802 insertPoint.parentNode.insertBefore(load_vset,insertPoint.nextSibling);
803 else insertPoint.parentNode.appendChild(load_vset);
805 var callback = function(index,photos,total,wait) {
807 var max = photos.length;
808 config.photos = photos;
809 if( photos.length<=0 ) {
810 insertPoint.parentNode.removeChild(load_vset);
813 for(var i=0;i<photos.length;i++) if(!photos[i]) {
814 if(DEBUG) GM_log(config.title + ' not loaded yet ' + i +','+total);
818 function showSet(page) {
820 var total = photos.length;
821 if(page==undefined) page=1;
822 pages = (total-total%perpage)/perpage+1;
823 var str = '<table cellspacing="30">';
825 str += '<td><h2>'+config.title+'</h2></td>';
826 str += '<td align="right"><a href="javascript:;" onclick="this.parentNode.parentNode.parentNode.parentNode.parentNode.style.display=\'none\';">Close</a></td>';
828 str += '<tr><td width="240" valign="top">';
829 str += '<p><img src="' +photos[0].img_m+ '"></p>';
830 str += '<p><small>There are ' + total + ' photos in this virtual set.</small></p>';
832 str += '<p><b>Add to a real set?</b><br /><a href="javascript:;" onclick="addtoSet[\''+id+'\'](false)">Add to an existing set</a> | <a href="javascript:;" onclick="addtoSet[\''+id+'\'](true)">Add to a new set</a></p>';
833 str += '<div id="photoset_list"></div>';
834 str += '<p><span id="vset_log"></span></p>';
837 str += '<td width="320" valign="top"><div style="width:320px">';
838 var num = ((total/perpage)>page)? page*perpage: total;
839 if(DEBUG) GM_log('Page=' + page +' total='+total+' num='+num);
840 for(var i=(page-1)*perpage;i<num;i++)
841 str += '<a href="' +photos[i].url+ '" class="thumb_link"><img src="' +photos[i].img_s+ '" width=75 height=75 style="margin:0px 3px 3px 0px;" /></a>';
842 str += '</div></td></tr>';
843 str += '<tr><td colspan="2" align="center"><div class="Paginator">';
844 for(i=1;i<=pages;i++) {
845 if(i==page) str += '<span class="this-page">'+i+'</span>';
846 else str += '<a title="'+id+'" href="#vset" onclick="showSet[\''+id+'\']('+i+')">'+i+'</a> ';
848 str += '</div></td></tr></table>';
849 if( !_gi('setdiv_'+config.title) ) {
851 setDiv.id = 'setdiv_'+config.title;
852 setDiv.style.position = 'absolute';
853 setDiv.style.overflow = 'visible';
854 setDiv.style.width = '650px';
855 setDiv.style.padding = '0px 25px 0px 25px';
856 setDiv.style.margin = '4px';
857 setDiv.style.zIndex = 1000;
858 setDiv.style.display = 'none';
859 setDiv.style.border = '15px solid #eaeaea';
860 setDiv.style.background = '#ffffff';
861 if( insertPoint.nextSibling ) insertPoint.parentNode.insertBefore(setDiv,insertPoint.nextSibling);
862 else insertPoint.parentNode.appendChild(setDiv);
865 setDiv.parentNode.insertBefore(ntag,setDiv);
866 } else setDiv = _gi('setdiv_'+config.title);
867 setDiv.innerHTML = str;
869 w.showSet[id] = showSet;
871 function addtoSet(newset,setid,setitle) {
873 var photosetid,photoseturl,ok=1,fail=0;
875 function addPhoto(id) {
876 if(DEBUG) GM_log('add photo #' + id);
878 if(setitle!=undefined) title = setitle;
879 _gi('vset_log').innerHTML += '<p>Adding Completed.<br />Goto the set "<a href="'+photoseturl+'">'+title+'</a>".</p>';
882 var url = 'http://www.flickr.com/services/rest/?' + sign({
883 method:'flickr.photosets.addPhoto',
884 photoset_id: photosetid,
885 photo_id: photos[id].id
888 method: 'GET', url: url, headers: headers,
889 onload: function(responseDetails) {
890 var parser = new w.DOMParser();
891 var dom = parser.parseFromString(responseDetails.responseText, "application/xml");
892 var stat = dom.getElementsByTagName('rsp')[0].getAttribute('stat');
893 if( stat == 'ok' ) ok++;
896 if(DEBUG) GM_log(responseDetails.responseText);
898 _gi('vset_log').innerHTML = ok + ' photos added ';
899 _gi('vset_log').innerHTML += (fail) ? (', ' + fail +' photos fail.') : '';
907 var title = prompt('New set title?');
908 if(title==null) return;
909 max = prompt('How many photos to add?\n (can use to add your top N photos or the first N photos in virtual set)',max);
911 if( max<=0 || max>photos.length) return;
912 var url = 'http://www.flickr.com/services/rest/?' + sign({
913 method:'flickr.photosets.create',
915 primary_photo_id: photos[0].id
917 if(DEBUG) GM_log(url);
919 method: 'GET', url: url, headers: headers,
920 onload: function(responseDetails) {
921 var parser = new w.DOMParser();
922 var dom = parser.parseFromString(responseDetails.responseText, "application/xml");
923 var stat = dom.getElementsByTagName('rsp')[0].getAttribute('stat');
925 _gi('vset_log').innerHTML = 'Creating set....';
926 photosetid = dom.getElementsByTagName('photoset')[0].getAttribute('id');
927 photoseturl = dom.getElementsByTagName('photoset')[0].getAttribute('url');
930 var err = dom.getElementsByTagName('err')[0].getAttribute('msg');
931 _gi('vset_log').innerHTML = 'Photoset created fail: ' + err;
936 if(setid==-1) return;
937 if(setid==undefined) {
938 max = prompt('How many photos to add?\n (can use to add your top N photos or the first N photos in virtual set)',max);
940 if( max<=0 || max>photos.length) return;
941 _gi('vset_log').innerHTML = 'Loading your photosets....';
942 var url = 'http://www.flickr.com/services/rest/?' + sign({
943 method:'flickr.photosets.getList'
946 method: 'GET', url: url, headers: headers,
947 onload: function(responseDetails) {
948 _gi('vset_log').innerHTML = '';
949 var parser = new w.DOMParser();
950 var dom = parser.parseFromString(responseDetails.responseText, "application/xml");
951 var stat = dom.getElementsByTagName('rsp')[0].getAttribute('stat');
953 var photosets = dom.getElementsByTagName('photoset');
954 var str = '<select onchange="addtoSet[\''+id+'\'](false,this.value,this.options[this.selectedIndex].text)"><option value="-1">Select Photoset....</optiom>';
955 for(var i=0;i<photosets.length;i++) {
956 photosetid = photosets[i].getAttribute('id');
957 primary = photosets[i].getAttribute('primary');
958 secret = photosets[i].getAttribute('secret');
959 server = photosets[i].getAttribute('server');
960 photoseturl = 'http://www.flickr.com/photos/'+global_nsid+'/sets/'+photosetid+'/';
961 text = new String(photosets[i].getElementsByTagName('title').item(0).firstChild.data);
962 title = text.substr(0,25) + ((text.length>25)?'...':'');
963 str += '<option value="'+photosetid+'">'+title+'</option>';
966 _gi('photoset_list').innerHTML = str;
968 var err = dom.getElementsByTagName('err')[0].getAttribute('msg');
969 _gi('vset_log').innerHTML = 'Photoset created fail: ' + err;
976 photoseturl = 'http://www.flickr.com/photos/'+global_nsid+'/sets/'+photosetid+'/';
981 w.addtoSet[id] = addtoSet;
983 _gi('vsethumb_' +id).src = photos[0].img_s;
984 // _gi('vsetlink_' +id).href = photos[0].url;
985 _gi('vsetlink_' +id).href = 'javascript:;';
986 _gi('vsetlink_' +id).addEventListener('click', function() {
987 if( !_gi('setdiv_'+config.title) ) {
990 if( setDiv.style.display == 'none' ) setDiv.style.display = 'block';
991 else setDiv.style.display = 'none';
993 _gi('vsetlink2_' +id).href = 'javascript:;';
994 _gi('vsetlink2_' +id).addEventListener('click', function() {
995 if( !_gi('setdiv_'+config.title) ) {
998 if( setDiv.style.display == 'none' ) setDiv.style.display = 'block';
999 else setDiv.style.display = 'none';
1001 _gi('vsetnum_' +id).innerHTML = photos.length;
1003 // config.api_paged = false;
1004 // config.params.per_page=1;
1005 if(!config.funct) var stream = new searchPhoto(config.params,callback, this.photos, config.api_paged, config.filters);
1006 else var stream = new config.funct(config.params,callback, this.photos, config.api_paged, config.filters);
1009 function showVirtualSet() {
1012 function getGroupId(vset) {
1013 var group_name = /\/in\/pool-([^\/]+)/.exec(document.location.pathname);
1015 group_name = group_name[1];
1016 vsets[vset].config.browse = 'http://www.flickr.com/groups/'+group_name+'/pool/'+vsets[vset].config.params.user_id+'/';
1017 vsets[vset].config.params.group_id = w.nextprev_currentContextID.replace(/pool/,'');
1018 vsets[vset].config.group_name = group_name;
1020 var url = 'http://www.flickr.com/services/rest/?' + sign({
1021 method:"flickr.urls.lookupGroup",
1022 url: "http://www.flickr.com/groups/"+group_name
1025 method: 'GET', url: url, headers: headers,
1026 onload: function(responseDetails) {
1027 var params = vsets[vset].config;
1028 params.browse = 'http://www.flickr.com/groups/'+group_name+'/pool/'+params.params.user_id+'/';
1029 var matches = /id="(.+?)"/.exec(responseDetails.responseText);
1030 if(matches) params.params.group_id = matches[1];
1031 vsets[vset].config.group_name = group_name;
1032 vsets[vset].stream = new Photostream(vsets[vset].config);
1038 function newPStreams() {
1039 var re = /http:\/\/(www\.)?flickr\.com\/photos\/[^\/]+\/\d+/;
1040 if( ! re.test(document.location) ) return;
1043 if(vsets['vset3'].enabled() && !vsets['vset3'].stream && isPublic == 0 ) vsets['vset3'].stream = new Photostream(private);
1044 if(vsets['vset8'].enabled() && !vsets['vset8'].stream && _gi('fave_countSpan').innerHTML != '0 people' ) vsets['vset8'].stream = new Photostream(favorited);
1045 if(vsets['vset10'].enabled() && !vsets['vset10'].stream ) vsets['vset10'].stream = new Photostream(yourinteresting);
1046 if(vsets['vset11'].enabled() && !vsets['vset11'].stream && (document.location.pathname.indexOf('/in/pool-') >= 0)) vsets['vset11'].stream = new Photostream(vsets['vset11'].config);
1048 if(vsets['vset1'].enabled() && !vsets['vset1'].stream && _gi('photo_gne_button_add_to_faves').src.match(/\/a_fave_grey.gif/) ) vsets['vset1'].stream = new Photostream(favorites);
1049 if(vsets['vset7'].enabled() && !vsets['vset7'].stream && _gi('photo_gne_button_add_to_faves').src.match(/\/a_fave_grey.gif/) ) vsets['vset3'].stream = new Photostream(favorites2);
1050 if(vsets['vset2'].enabled() && !vsets['vset2'].stream ) vsets['vset2'].stream = new Photostream(contacts);
1051 if(vsets['vset9'].enabled() && !vsets['vset9'].stream ) vsets['vset9'].stream = new Photostream(userinteresting);
1052 if(vsets['vset12'].enabled() && !vsets['vset12'].stream && (document.location.pathname.indexOf('/in/pool-') >= 0)) vsets['vset12'].stream = new Photostream(vsets['vset12'].config);
1055 if(vsets['vset4'].enabled() && !vsets['vset4'].stream ) vsets['vset4'].stream = new Photostream(interestingness);
1056 if(vsets['vset13'].enabled() && !vsets['vset13'].stream ) vsets['vset13'].stream = new Photostream(relevantphotos);
1058 if(vsets['vset5'].enabled() && !vsets['vset5'].stream ) {
1059 for(var i in global_photos[photo_id].tagsA )
1060 if( global_photos[photo_id].tagsA[i] == 'geotagged' )
1061 vsets['vset5'].stream = new Photostream(geotagged);
1064 if( vsets['vset6'].enabled() && !vsets['vset6'].stream && isPublic == 0 ) vsets['vset6'].stream = new Photostream(friends);
1067 function newVsets() {
1068 var re = /http:\/\/(www\.)?flickr\.com\/photos\/[^\/]+\/sets\//;
1069 var re2 = /http:\/\/(www\.)?flickr\.com\/photos\/[^\/]+\/sets\/\d+\//;
1070 if( ! re.test(document.location) || re2.test(document.location) ) return;
1072 if(DEBUG) GM_log('In set page ' + isOwner);
1075 if(vsets['vset3'].enabled() && !vsets['vset3'].stream ) vsets['vset3'].stream = new VirtualSet(private);
1076 if(vsets['vset8'].enabled() && !vsets['vset8'].stream ) vsets['vset8'].stream = new VirtualSet(favorited);
1077 if(vsets['vset10'].enabled() && !vsets['vset10'].stream ) vsets['vset10'].stream = new VirtualSet(yourinteresting);
1079 // if(vsets['vset1'].enabled() && !vsets['vset1'].stream ) vsets['vset1'].stream = new VirtualSet(favorites);
1080 if(vsets['vset7'].enabled() && !vsets['vset7'].stream ) vsets['vset3'].stream = new VirtualSet(favorites2);
1081 // if(vsets['vset2'].enabled() && !vsets['vset2'].stream ) vsets['vset2'].stream = new VirtualSet(contacts);
1082 if(vsets['vset9'].enabled() && !vsets['vset9'].stream ) vsets['vset9'].stream = new VirtualSet(userinteresting);
1084 if(vsets['vset4'].enabled() && !vsets['vset4'].stream ) {
1085 // vsets['vset4'].stream = new VirtualSet(interestingness);
1088 if(vsets['vset5'].enabled() && !vsets['vset5'].stream ) vsets['vset5'].stream = new VirtualSet(geotagged);
1089 if(vsets['vset6'].enabled() && !vsets['vset6'].stream ) vsets['vset6'].stream = new VirtualSet(friends);
1090 if(vsets['vset13'].enabled() && !vsets['vset13'].stream ) vsets['vset13'].stream = new VirtualSet(relevantphotos);