// ==UserScript== // @name Yphotoalbum // @namespace http://tsuyuguchi.com/ // @include http://album.yahoo.co.jp/* // ==/UserScript== /*** Change Logs *****************************/ /* version: 0.0.9 - 2008/05/14 show flickr icon in masthead version: 0.0.8 - 2008/05/14 reload after id tie setting changed version: 0.0.7 - 2008/05/14 show msg when flickr photos|sets is empty. version: 0.0.6 - 2008/04/17 support video thumbnails version: 0.0.5 - 2008/04/09 change internal stored data handling version: 0.0.4 - 2008/04/08 show friends' flickr account on http://album.yahoo.co.jp/friends/* version: 0.0.3 - 2008/04/08 change Xpath from which value of friend_key is got. version: 0.0.2 - 2008/04/07 some bugs fixed version: 0.0.1 - 2008/04/05 initial version */ (function(){ /****** Config ***********************/ // Tab var tab_config = [ { txt : "Flickr", url : function(){ return "http://www.flickr.com/photos/"+user_id+"/"; } }, { txt : "Contact List", url : function(){ return "http://www.flickr.com/people/"+user_id+"/contacts/"; } }, null ]; /****** Global Variables *************/ var yid = ""; var api_key = ""; var user_id = ""; var username = ""; var friend_key = ""; var friend_id = ""; var friend_username = ""; var now_url = location.href; /****** Const ************************/ var flickr_entrypoint = "http://api.flickr.com/services/rest/?"; /****** functions called as JSONP CallBack *********************/ var setUserId = function( obj ){ if( obj.code ){ if( obj.code == 100 ){ error_api_key_invalid(); } if( obj.code == 1 ){ alert( "'"+username+"' is not found in Flickr"); userinfo.clear('username'); userinfo.write(); } return; } user_id = obj.user.id; userinfo.set( 'user_id', user_id ); userinfo.write(); } var setFriendUserId = function( obj ){ if( obj.code ){ if( obj.code == 100 ){ error_api_key_invalid(); } if( obj.code == 1 ){ alert( "'"+friend_username+"' is not found in Flickr"); friendinfo.clear(friend_key); friendinfo.write(); } return; } friend_id = obj.user.id; friendinfo.set( friend_key, 'id', friend_id ); friendinfo.set( friend_key, 'username', friend_username ); friendinfo.write(); var profile_name = findElementsByXpath('//div[@id="yahooIdentityUserCard"]/div[@class="roundCornerBox"]/div[@class="roundCornerMiddle"]' + '/div[@class="roundCornerBox"]/div[@class="roundCornerMiddle"]/div[@class="yahooIdentityUserCardContents"]' + '/span[@class="yahooIdentityUserCardTitle"]').snapshotItem(0).innerHTML; profile_name = profile_name.replace( //g, '' ); alert( '"' + profile_name + '" と Flickr id:' + friend_username + ' を連携させました。' ); location.reload(); } var showContactPhotos = function( obj ){ if( obj.code == 100 ){ error_api_key_invalid(); return; } var div = document.getElementById('flickrcontactphoto'); var panel = genTopPageContainer( div, 'Flickr Contacts Photos', 'http://www.flickr.com/photos/friends/' ); var photos = obj.photos.photo; var len = photos.length; for( var i = 0; i < len; i++ ){ var node = createPhotoPanel( photos[i], i == len - 1 ); panel.appendChild( node ); } } var showInterestingness = function( obj ){ if( obj.code == 100 ){ error_api_key_invalid(); return; } var div = document.getElementById('flickrinterestingness'); var panel = genTopPageContainer( div, 'Flickr Interestingness', 'http://www.flickr.com/explore/interesting/' ); var photos = obj.photos.photo; var len = photos.length; for( var i = 0; i < len; i++ ){ var node = createPhotoPanel( photos[i], i == len - 1 ); panel.appendChild( node ); } } var showFlickrPhotos = function( obj ){ if( obj.code == 100 ){ error_api_key_invalid(); return; } var div = document.getElementById('flickrphotos'); var photos = obj.photos.photo; var len = photos.length; if( len == 0 ){ genEmptyContainer( div, 'Flickr Photo', 'Flickr Photo はありません。' ); return; } var panel = genTopPageContainer( div, 'Flickr Photo', genUserTopUrl( friend_id || user_id ) ); for( var i = 0; i < len; i++ ){ var node = createPhotoPanel( photos[i], i == len - 1, true ); panel.appendChild( node ); } }; var showFlickrSets = function( obj ){ if( obj.code == 100 ){ error_api_key_invalid(); return; } var div = document.getElementById('flickrsets'); var photosets = obj.photosets.photoset; var len = photosets.length < 5 ? photosets.length : 5 if( len == 0 ){ genEmptyContainer( div, 'Flickr Sets', 'Flickr Set はありません。' ); return; } var panel = genTopPageContainer( div, 'Flickr Sets', genUserSetListPage( friend_id || user_id ) ); for( var i = 0; i < len; i++ ){ var node = createPhotoSetPanel( photosets[i], i == len - 1, true ); panel.appendChild( node ); } } var showFlickrContact = function( obj ){ var node = findElementsByXpath('//div[@id="yahooIdentityContactBadge"]/div[@class="yahooIdentityContactBadgeBGtop"]/div[@class="yahooIdentityContactBadgePanelRow clearFix"]').snapshotItem(0); if( obj.contacts.total == 0 ){ // no contacts return; } var contacts = obj.contacts.contact; var len = contacts.length; var div = createNode('div'); var rowcontainer = null; for( var i = 0; i < len; i++ ){ var icon = genContactIcon( contacts[i], i%3 == 2 ); if( i%3 == 0 ) rowcontainer = createNode('div','yahooIdentityContactBadgePanelRow clearFix'); rowcontainer.appendChild( icon ); if( i%3 == 2 || i == len - 1 ) div.appendChild( rowcontainer ); } node.parentNode.insertBefore( div, node ); var node = findElementsByXpath('//div[@id="yahooIdentityContactBadge"]/div[@class="yahooIdentityContactBadgeBGtop"]/div[@class="yahooIdentityContactBadgeTitle"]').snapshotItem(0); node.innerHTML += '(Flickr:'+obj.contacts.total+'人)'; var node = findElementsByXpath('//div[@id="yahooIdentityContactBadge"]/div[@class="yahooIdentityContactBadgeBGtop"]/div[@class="yahooIdentityContactBadgeSeeAll"]').snapshotItem(0); node.innerHTML += '
' + createSeeAll( genContactListPageUrl( friend_id || user_id ), 'Flickr Contacts' ); } /****** Common Functions *************/ var showFlickrMasthead = function(){ var node = findElementsByXpath('//div[@class="yjmthproplogoarea"]').snapshotItem(0); node.innerHTML += 'meets '; } var createTab = function(){ var node = findElementsByXpath('//div[@id="header"]/div[@class="navigationMain"]/div[@class="navigationTab"]').snapshotItem(0); for( var i = 0; tab_config[i]; i++ ){ var txt = tab_config[i].txt; txt = (typeof(txt) == 'function') ? txt() : txt; var url = tab_config[i].url; url = (typeof(url) == 'function') ? url() : url; var left = createNode('div', 'navigationLeft'); var center = createNode('div', 'navigationCenter'); center.innerHTML = ''+txt+''; var right = createNode('div', 'navigationRight'); node.appendChild(left); node.appendChild(center); node.appendChild(right); } }; var createPhotoPanel = function( photoObj, isLast, isPreferTitle ){ var panel = createNode('div', isLast ? 'panelContainerRight':'panelContainer' ); var photo = createNode('span', 'photoContainer'); var name = createNode('span', 'nameContainer'); var owner = photoObj.owner; var username = photoObj.username; var title = photoObj.title; var media = photoObj.media; if( media == 'photo' ){ photo.innerHTML = ''; } else{ // video photo.innerHTML = genVideoThumbnailUrl(photoObj); } if( isPreferTitle && title ){ name.innerHTML = ''+title+''; } else if( username ){ name.innerHTML = ''+username+''; } else if( owner ){ name.innerHTML = ''+owner+''; var url = flickr_entrypoint + "method=flickr.people.getInfo" + "&api_key="+api_key+"&user_id="+owner+"&format=json&nojsoncallback=1"; GM_xmlhttpRequest( genHttpRequestObj( url, genFuncToShowUserName(name) ) ); } panel.appendChild( photo ); panel.appendChild( name ); return panel; } var createPhotoSetPanel = function( photosetObj, isLast, isPreferTitle ){ var panel = createNode('div', isLast ? 'panelContainerRight':'panelContainer' ); var photo = createNode('span', 'photoContainer'); var name = createNode('span', 'nameContainer'); var title = photosetObj.title._content; photo.innerHTML = ''; name.innerHTML = ''+title+''; panel.appendChild( photo ); panel.appendChild( name ); return panel; } var genContactIcon = function( contactObj, isLast ){ var container = createNode('div', isLast ? 'yahooIdentityContactBadgePanelContainerRightend':'yahooIdentityContactBadgePanelContainer'); var panel = createNode('div', 'yahooIdentityContactBadgePanel' ); var name = createNode('div', 'clearFix' ); var id = contactObj.nsid; panel.innerHTML = '
' + ''; + '
'; name.innerHTML = ''+contactObj.username+''; container.appendChild( panel ); container.appendChild( name ); return container; } var genEmptyContainer = function( div, title, msg ){ var title = createNode('div', 'title', '

'+title+'

'); var empty = createNode('div', 'emptyBox', msg ); div.appendChild( title ); div.appendChild( empty ); } var genTopPageContainer = function( div, title, all_url ){ var title = createNode('div', 'title', '

'+title+'

'); var container = createNode('div', 'containerDot'); var panel = createNode('div', 'panelRow clearFix'); var seeall = createNode('div', 'seeAll', createSeeAll( all_url ) ); div.appendChild( title ); div.appendChild( container ); container.appendChild( panel ); div.appendChild( seeall ); return panel; } var genFuncToShowUserName = function( node ){ return function( res ){ if( res.status != 200 ) return; var userinfo = eval( '(' + res.responseText + ')' ); var username = userinfo.person.username._content; var url = userinfo.person.photosurl._content; node.innerHTML = ''+username+''; } } /****** Utility Functions ************/ var findElementsByXpath = function( xpath ){ return document.evaluate( xpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); } var getYid = function(){ var node = findElementsByXpath( '//div[@id="masthead"]/div[@class="yjmth"]/div[@class="yjmthloginarea"]/strong' ).snapshotItem(0); var txt = node.innerHTML; return txt.match( /^[_a-zA-Z0-9]+$/ ) ? txt : ""; } /******* DOM Utility function ********************/ var createNode = function( tag, class, innerHTML ){ var node = document.createElement(tag); if( class ){ node.setAttribute('class', class); } if( innerHTML ){ node.innerHTML = innerHTML; } return node; } var createSeeAll = function( url, txt ){ if( !txt ) txt = '一覧'; return '一覧'+txt+''; } /****** Error Handling functions ****************/ var error_api_key_invalid = function(){ alert( "Flickr api key is invalid"); userinfo.clear('api_key'); userinfo.write(); } /****** GM storage utility functions ***********/ var userinfo = { _hash : {}, _init : false, _dirty : false, _initialize : function(){ this._read(); this._init = true; }, _read : function(){ if( !this._dirty ){ this._hash = eval("("+GM_getValue("_hash")+")") || {}; } }, write : function(){ if( this._dirty ){ GM_setValue( "_hash", this._hash.toSource() ); this._dirty = false; } }, set : function( key, value ){ var initialize = false; if( !this._init ){ this._initialize(); initialize = true; } if( !value ) delete this._hash[key]; else this._hash[key] = value; this._dirty = true; }, get : function( key ){ if( !this._init ){ this._initialize(); } return this._hash[key]; }, clear : function( key ){ if( !this._init ){ this._initialize(); } this.set(key, null); } }; var friendinfo = { _hash : {}, _init : false, _dirty : false, _initialize : function(){ this._read(); this._init = true; }, _read : function(){ if( !this._dirty ){ this._hash = eval("("+GM_getValue("_friend")+")") || {}; } }, write : function(){ if( this._dirty ){ GM_setValue( "_friend", this._hash.toSource() ); this._dirty = false; } }, set : function( friend_key, key, value ){ var initialize = false; if( !this._init ){ this._initialize(); initialize = true; } if( !this._hash[friend_key] ) this._hash[friend_key] = {}; if( !key && this._hash[friend_key] ) delete this._hash[friend_key]; else if( !value ) delete this._hash[friend_key][key]; else this._hash[friend_key][key] = value; if( !initialize ) this._dirty = true; }, get : function( friend_key, key ){ if( !this._init ){ this._initialize(); } if( key == null ){ return this._hash[friend_key]; } return this._hash[friend_key] ? this._hash[friend_key][key] : null; }, clear : function( friend_key, key ){ if( !this._init ){ this._initialize(); } if( key ) this.set(friend_key, key, null); else this.set(friend_key, null, null); } }; /**** Flickr utility functions *********************************************/ var genPhotoThumbnailUrl = function( photoObj ){ return 'http://farm'+photoObj.farm+'.static.flickr.com/'+photoObj.server+'/'+photoObj.id+'_'+photoObj.secret+'_t.jpg'; } var genVideoThumbnailUrl = function( photoObj ){ var secret = photoObj.secret; var id = photoObj.id; return '' + '' + '' + '' + ''; } var genPhotoPageUrl = function( photoObj ){ return 'http://www.flickr.com/photos/'+ photoObj.owner+'/'+ photoObj.id+'/'; } var genUserTopUrl = function( user_id ){ return 'http://www.flickr.com/photos/'+user_id+'/'; } var genUserSetListPage = function( user_id ){ return 'http://www.flickr.com/photos/'+user_id+'/sets/'; } var genPhotoSetThumbnailUrl = function( photosetObj ){ return 'http://farm'+photosetObj.farm+'.static.flickr.com/'+photosetObj.server+'/'+photosetObj.primary+'_'+photosetObj.secret+'_s.jpg'; } var genPhotoSetUrl = function( photosetObj, user_id ){ return 'http://www.flickr.com/photos/'+user_id+'/sets/'+photosetObj.id+'/'; } var genContactIconImgUrl = function( contactObj ){ return ( contactObj.iconserver != 0 ) ? 'http://farm'+contactObj.iconfarm+'.static.flickr.com/'+contactObj.iconserver+'/buddyicons/'+contactObj.nsid+'.jpg' : 'http://l.yimg.com/www.flickr.com/images/buddyicon.jpg'; } var genContactListPageUrl = function( user_id ){ return 'http://www.flickr.com/people/'+user_id+'/contacts/'; } var genUserProfilePageUrl = function( user_id ){ return 'http://www.flickr.com/people/'+user_id+'/'; } /**** XHR utility functions ************************************************/ var eval_jsonp = function( res ){ if( res.status != 200 ) return; eval( res.responseText ); }; var genHttpRequestObj = function( url, callback ){ return { method: 'GET', url: url, onload: callback }; }; /**** Other Functions ******************************************************************/ var tieUpFlickrUsername = function(){ friend_username = document.getElementById('flickrfriendusername').value; if( !friend_username ){ friendinfo.clear(friend_key); friendinfo.write(); alert("連携をやめました"); location.reload(); return; } var url = flickr_entrypoint + "method=flickr.people.findByUsername" + "&api_key="+api_key+"&username="+friend_username+"&format=json&jsoncallback=setFriendUserId"; GM_xmlhttpRequest( genHttpRequestObj( url, eval_jsonp ) ); } /***********************************************************************/ var pre_main = function(){ if( !(yid = getYid()) ) return false; api_key = userinfo.get('api_key'); if( !api_key ){ api_key = prompt("input your Flickr API key"); if( !api_key ) return false; userinfo.set('api_key', api_key ); userinfo.write(); } username = userinfo.get('username'); if( !username ){ username = prompt("input your Flickr username"); if( !username ) return false; userinfo.set('username',username); userinfo.write(); } user_id = userinfo.get('user_id'); if( !user_id ){ var url = flickr_entrypoint + "method=flickr.people.findByUsername" + "&api_key="+api_key+"&username="+username+"&format=json&jsoncallback=setUserId"; GM_xmlhttpRequest( genHttpRequestObj( url, eval_jsonp ) ); } return true; } var retryMax = 5; var retry = 0; var call_main_if_user_id_is_loaded = function(){ if( user_id ){ main(); return; } if( retry++ < retryMax ) setTimeout( call_main_if_user_id_is_loaded, 1000 ); } var show_flickr_images_on_sub = function( id ){ var target = findElementsByXpath('//div[@id="sub"]/div[@class="moduleTypeM"]').snapshotItem(0); var div1 = createNode('div', 'myPhoto moduleTypeM'); div1.id = 'flickrphotos'; var div2 = createNode('div', 'myPhoto moduleTypeM'); div2.id = 'flickrsets'; target.parentNode.insertBefore( div1, target ); target.parentNode.insertBefore( div2, target ); url = flickr_entrypoint + "method=flickr.people.getPublicPhotos" + "&api_key="+api_key+"&user_id="+id+"&per_page=5&extras=farm,media&format=json&jsoncallback=showFlickrPhotos"; GM_xmlhttpRequest( genHttpRequestObj( url, eval_jsonp ) ); url = flickr_entrypoint + "method=flickr.photosets.getList" + "&api_key="+api_key+"&user_id="+id+"&format=json&jsoncallback=showFlickrSets"; GM_xmlhttpRequest( genHttpRequestObj( url, eval_jsonp ) ); url = flickr_entrypoint + "method=flickr.contacts.getPublicList" + "&api_key="+api_key+"&user_id="+id+"&per_page=9&format=json&jsoncallback=showFlickrContact"; GM_xmlhttpRequest( genHttpRequestObj( url, eval_jsonp ) ); } var show_friends_flickr_profile_link = function(){ var target = findElementsByXpath('//div[@id="sub"]//span[@class="nameContainer"]/strong'); var len = target.snapshotLength; for( var i = 0; i < len; i++ ){ var node = target.snapshotItem(i); node.getElementsByTagName('a')[0].getAttribute('href').match(/profile-(.*)$/); var friend_key = RegExp.$1; var user = friendinfo.get( friend_key ); node.innerHTML = ' ' + node.innerHTML; if( !user ) continue; node.innerHTML += '
'+user.username+''; } } var main = function(){ var url = ""; showFlickrMasthead(); createTab(); if( now_url == 'http://album.yahoo.co.jp/' ){ var target = findElementsByXpath('//div[@id="main"]/div[@class="friendNewPhoto moduleTypeM"]').snapshotItem(0); var div1 = createNode('div', 'friendNewPhoto moduleTypeM'); div1.id = 'flickrinterestingness'; var div2 = createNode('div', 'friendNewPhoto moduleTypeM'); div2.id = 'flickrcontactphoto'; target.parentNode.insertBefore( div1, target ); target.parentNode.insertBefore( div2, target ); url = flickr_entrypoint + "method=flickr.photos.getContactsPublicPhotos" + "&api_key="+api_key+"&user_id="+user_id+"&count=5&extras=farm,media&format=json&jsoncallback=showContactPhotos"; GM_xmlhttpRequest( genHttpRequestObj( url, eval_jsonp ) ); url = flickr_entrypoint + "method=flickr.interestingness.getList" + "&api_key="+api_key+"&per_page=5&extras=farm,media&format=json&jsoncallback=showInterestingness"; GM_xmlhttpRequest( genHttpRequestObj( url, eval_jsonp ) ); } else if ( now_url == 'http://album.yahoo.co.jp/photos/my/' ){ show_flickr_images_on_sub( user_id ); } else if ( now_url.match( /^http:\/\/album\.yahoo\.co\.jp\/(?:profile-.*|photos\/my\/\d+\/)$/ ) ) { var target = findElementsByXpath('//form[@action="http://profiles.yahoo.co.jp/-/userbadge/redirect/"]/input[@name="target"]').snapshotItem(0); friend_key = target.value; friend_username = friendinfo.get(friend_key,'username') || ""; friend_id = friendinfo.get(friend_key,'id') || ""; target = findElementsByXpath('//div[@id="yahooIdentityUserCard"]/div[@class="roundCornerBox"]/div[@class="roundCornerMiddle"]' + '/div[@class="roundCornerBox"]/div[@class="roundCornerMiddle"]/div[@class="yahooIdentityUserCardContents"]' + '/div[@class="clearFix"]' ).snapshotItem(0); target.innerHTML += '
Flickr username:'; var button = document.createElement('input'); button.setAttribute('type','button'); button.setAttribute('value','連携'); button.addEventListener('click', tieUpFlickrUsername, false ); target.appendChild( button ); if( !friend_id ) return; show_flickr_images_on_sub( friend_id ); } else if ( now_url.match( /^http:\/\/album\.yahoo\.co\.jp\/friends\// ) ){ show_friends_flickr_profile_link(); } } /******* body of this Greasemonkey ****************/ if( !pre_main() ){ return; } call_main_if_user_id_is_loaded(); })();