4 // Copyright (c) 2006, Pierre Andrews.
5 // Released under the GPL license
6 // http://www.gnu.org/copyleft/gpl.html
10 // @namespace http://6v8.gamboni.org/Flickr-Snap.html
11 // @description Add thumbnails of flickr image where a link goes there.
12 // @source http://6v8.gamboni.org/Flickr-Snap.html
13 // @identifier http://6v8.gamboni.org/IMG/js/flickrsnap.user.js
16 // @creator Pierre Andrews (mortimer.pa@free.fr)
18 // @exclude http://flickr.com*
19 // @exclude http://www.flickr.com*
20 // @exclude http:/del.icio.us*
25 var win
= (unsafeWindow
|| window
.wrappedJSObject
|| window
);
30 namespace: "http://6v8.gamboni.org/Flickr-Snap.html",
31 description
: "Add thumbnails of flickr image where a link goes there.",
32 source
: "http://6v8.gamboni.org/Flickr-Snap.html", // script homepage/description URL
33 identifier
: "http://6v8.gamboni.org/IMG/js/flickrsnap.user.js",
34 version
: "0.1", // version
35 date
: (new Date(2006, 5, 09)) // update date
39 //======================================================================
42 //======================================================================
45 // http status constants
48 // xmlhttprequest readystate
53 //======================================================================
55 var procException = function(msg
, code
, req
) {
62 //======================================================================
63 //to do the closure and get the right this.
64 //adapted from http://persistent.info/greasemonkey/gmail.user.js
66 function getObjectMethodClosure(object
, method
) {
68 return object
[method
]();
72 function getObjectMethodClosure0(object
, method
,args
) {
74 return object
[method
](args
);
78 function getObjectMethodClosure1(object
, method
) {
79 return function(arg
) {
80 return object
[method
](arg
);
85 function getObjectMethodClosure11(object
, method
,args3
) {
86 return function(arg
) {
87 return object
[method
](arg
,args3
);
91 function getObjectMethodClosure2(object
, method
) {
92 return function(arg
,arg2
) {
93 return object
[method
](arg
,arg2
);
96 function getObjectMethodClosure21(object
, method
,args3
) {
97 return function(arg
,arg2
) {
98 return object
[method
](arg
,arg2
,args3
);
105 //======================================================================
106 //Simple calls to flickr REST API, from the batch enhancer script
107 // needs the md5 and status_msg code above
109 win
.FlickrAPI = function(){;}
111 win
.FlickrAPI
.prototype = { // flickr api
113 init: function(api_key
,shared_secret
) {
114 this.api_key
= api_key
;
115 this.shared_secret
= shared_secret
;
116 if(shared_secret
) this.auth_token
= GM_getValue('auth_'+this.api_key
);
118 if (this.shared_secret
&& !this.auth_token
) {
124 askForAuth: function() {
125 this.flickr_api_call("flickr.auth.getFrob",
126 {api_sig
: this.getMethodSig("flickr.auth.getFrob", {api_key
: this.api_key
})},
127 getObjectMethodClosure2(this,'frob_loaded'),
128 getObjectMethodClosure1(this,'frob_failed'));
131 frob_loaded: function(req
, rsp
) {
133 this.frob
= rsp
..frob
[0];
134 if(DEBUG
) GM_log("received Frob "+this.frob
);
135 var api_sig
= this.getMethodSig(false, {api_key
: this.api_key
,frob
:this.frob
,perms
:"read"});
136 var url
= "http://flickr.com/services/auth/?api_key="+this.api_key
+"&perms=read&frob="+this.frob
+"&api_sig="+api_sig
;
137 //Here, we need the status_msg code
138 status_msg
.msgbox2("This script needs to be authorized. <br>" +
139 "<b style=\"font-variant:small-caps;\">Click [<a onclick='window.open(\""+url
+"\"); return false'>Step1</a>]</b>, " +
140 "follow the instructions in the popup window,<br> " +
141 "then return here click Step2.<br> " +
142 "Popup blockers may cause this not to work.<br>You'll only have to do this once.","Step2",getObjectMethodClosure1(this,'getToken'));
145 frob_failed: function(e
) {
146 status_msg
.msgbox('Couldn\'t authorize, for whatever reason.');
149 token_loaded: function(req
,rsp
) {
151 var token
= rsp
..token
[0];
152 this.nsid
= rsp
..user
.@nsid
[0];
154 if(DEBUG
) GM_log("authenticated with user "+this.nsid
+": "+token
);
157 GM_setValue('auth_'+this.api_key
,""+token
);
160 token_failed:function(e
) {
161 status_msg
.msgbox('Couldn\'t authorize, for whatever reason.');
168 status_msg
.show('authorizing...');
169 var api_sig
= this.getMethodSig("flickr.auth.getToken", {api_key
: this.api_key
,frob
:this.frob
});
170 this.flickr_api_call("flickr.auth.getToken",
171 {frob
: this.frob
,api_sig
: api_sig
},
172 getObjectMethodClosure2(this,'token_loaded'),
173 getObjectMethodClosure1(this,'token_failed'));
176 do_req: function ( method
, proc_request
, url
, referer
, data
) {
177 var headers
= new Object();
180 onload : function(d
) { proc_request(d
) },
186 headers
['Referer'] = referer
;
189 headers
['Content-Type'] = 'application/x-www-form-urlencoded';
190 details
['data'] = data
;
193 GM_xmlhttpRequest( details
);
198 // a proc just spins around waiting for the thing to succeed or fail
199 // then calls a callback, if we got 200 OK message.
200 make_proc: function (op_name
, ok_cb
, fail_cb
) {
202 return function(req
) {
206 document
.body
.style
.cursor
= 'progress';
208 if (req
.readyState
!= COMPLETE
) {
212 // if (alert_response) { alert(req.responseText); }
214 if( req
.status
!= OK
) {
215 throw new procException( op_name
+ " request status was '" + req
.status
+ "'", 0, req
)
223 document
.body
.style
.cursor
= 'default';
226 if (e
instanceof procException
) {
227 if( fail_cb
!= null )
232 GM_log(e
.req
.responseText
);
242 document
.body
.style
.cursor
= 'default';
247 // this is wraps the spinning proc like above,
248 // except it parses the flickr api response a little before deciding all is well,
249 // and passing control to the all-is-well callback
250 make_flickr_api_proc: function(op_name
, ok_cb
, fail_cb
) {
252 function parse_and_ok_cb(req
) {
253 if(DEBUG
) GM_log(req
.responseText
);
254 var rsp
= req
.responseText
.replace(/<\?xml.*\?>/,'');
255 var rsp
= new XML(rsp
);
256 // var rsp = req.responseXML.getElementsByTagName('rsp').item(0);
259 throw new procException( "Could not understand Flickr's response.", 0, req
);
262 var stat
= rsp
.@stat
;
264 throw new procException( "Could not find status of Flickr request", 0, req
);
268 if (stat
== 'fail') {
269 var err_node
= rsp
.err
[0];
270 var code
= err_node
.@code
;
271 var err_msg
= err_node
.@msg
;
272 throw new procException( err_msg
, code
, req
);
274 throw new procException("Unknown error status: '" + stat
+ "'", 0, req
)
281 return this.make_proc(op_name
, parse_and_ok_cb
, fail_cb
);
284 getMethodSig: function(method
, args
)
286 var data
= new Array();
287 var names
= new Array();
288 var sig
= this.shared_secret
;
291 data
['method'] = method
;
292 names
.push('method');
294 for (var key
in args
) {
295 data
[key
] = args
[key
];
300 sig
+= names
[i
] + data
[names
[i
]];
306 // construct a flickr api request, with method and args,
307 // if that worked, call callback with request object.
308 flickr_api_call: function( method
, args
, ok_cb
, fail_cb
,with_auth
) {
310 var http_method
= args
['http_method'];
311 http_method
= ( http_method
? http_method
: 'GET' );
312 delete args
['http_method'];
314 args
['api_key'] = this.api_key
;
316 if (this.shared_secret
&& with_auth
&& this.auth_token
) {
317 args
['auth_token'] = this.auth_token
;
318 args
['api_sig'] = this.getMethodSig(method
, args
);
319 } else if(DEBUG
) GM_log('not signing: ' + method
);
322 var url
= 'http://www.flickr.com/services/rest/?method=' + encodeURIComponent(method
);
324 for (var key
in args
) {
325 url
+= '&' + encodeURIComponent(key
) + '=' + encodeURIComponent(args
[key
]);
327 if(DEBUG
) GM_log(url
);
329 var proc
= this.make_flickr_api_proc( method
, ok_cb
, fail_cb
)
331 this.do_req(http_method
, proc
, url
, null, null)
336 //======================================================================
338 var MAX_DAY_COUNT
= 5;
339 var NUMBER_OF_LAST_PHOTOS
= 8;
341 win
.FlickrSnap = function() {;}
344 win
.FlickrSnap
.prototype = {
345 init: function(key
,secret
) {
346 this.api
= new win
.FlickrAPI();
347 this.api
.init(key
,false);
348 var auctionLinks
= document
.evaluate(
350 document
, null, XPathResult
.UNORDERED_NODE_SNAPSHOT_TYPE
, null); // Get all group
352 for(var i
= 0; i
< auctionLinks
.snapshotLength
; i
++) { // For each LINK...
353 var al
= auctionLinks
.snapshotItem(i
);
357 checkImage: function(link
) {
358 for(var i
=0;i
<link
.childNodes
.length
;i
++) {
359 if(link
.childNodes
.item(i
).nodeName
== 'IMG') {
364 processA: function(link
) {
365 if(matches
= /^(http:\/\/)?(www\.)?flickr.com\/photos\/[^\/]+?\/([0-9]+)/i.exec(link
.href
)) {
366 if(!this.checkImage(link
)) { //the link is not on an image
367 this.api
.flickr_api_call('flickr.photos.getSizes',
368 { photo_id
: matches
[3], http_method
: 'POST' },
369 getObjectMethodClosure21(this,'getSizes_done', link
),
370 getObjectMethodClosure1(this,'request_failed'));
372 } else if(matches
= /^(http:\/\/)?(www\.)?flickr.com\/photos\/[^\/]+?\/sets\/([0-9]+)/i.exec(link
.href
)) {
373 if(!this.checkImage(link
)) { //the link is not on an image
374 this.api
.flickr_api_call('flickr.photosets.getPhotos',
375 { photoset_id
: matches
[3], http_method
: 'POST' },
376 getObjectMethodClosure21(this,'getSetPhotos_done', link
),
377 getObjectMethodClosure1(this,'request_failed'));
382 request_failed: function(err
) {
385 getSizes_done: function(req
,rsp
,link
) {
386 img
= link
.appendChild(document
.createElement('IMG'));
387 img
.src
= rsp
..size
.@source
[0];
389 getSetPhotos_done: function(req
,rsp
,link
) {
390 var primary
= rsp
..photo
.(@isprimary
== '1');
391 img
= link
.appendChild(document
.createElement('IMG'));
392 img
.src
= "http://static.flickr.com/"+primary
.@server
+"/"+primary
.@id
+'_'+primary
.@secret
+'_s.jpg';
396 // update automatically (http://userscripts.org/scripts/show/2296)
398 window
.addEventListener("load", function () {
400 win
.UserScriptUpdates
.requestAutomaticUpdates(SCRIPT
);
403 var flickrgp
= new win
.FlickrSnap();
404 flickrgp
.init( "e8c3239ff04c102ce2d6ed885bf99005");