WM Graph API Interface (Beta Branch)

Creates a low-access, read-only interface to the FB Graph API.

بۇ قوليازمىنى بىۋاسىتە قاچىلاشقا بولمايدۇ. بۇ باشقا قوليازمىلارنىڭ ئىشلىتىشى ئۈچۈن تەمىنلەنگەن ئامبار بولۇپ، ئىشلىتىش ئۈچۈن مېتا كۆرسەتمىسىگە قىستۇرىدىغان كود: // @require https://update.greatest.deepsurf.us/scripts/420/26698/WM%20Graph%20API%20Interface%20%28Beta%20Branch%29.js

  1. // ==UserScript==
  2. // @name WM Graph API Interface (Beta Branch)
  3. // @namespace MerricksdadGraphInterface
  4. // @description Creates a low-access, read-only interface to the FB Graph API.
  5. // @license http://creativecommons.org/licenses/by-nc-nd/3.0/us/
  6. // @version 3.2.3
  7. // @copyright Charlie Ewing except where noted
  8. // ==/UserScript==
  9.  
  10. //this script requires some functions in the WM Common Library
  11. //this script needs access to a pre-defined JSON object
  12.  
  13. var workOffline=false;
  14.  
  15. (function(){
  16. this.Graph = {
  17. posts: {}, //location to store adjusted post data
  18. authRequestOut: false, //dont ask for token while asking for token
  19. authToken: (isChrome||getOpt("disableSaveAuthToken"))?null:getOpt("lastAuthToken"), //use stored fb token
  20. userID: null,
  21. userAlias: null,
  22. userName: null,
  23. fetchTimeout: 30,
  24.  
  25. requests: [],
  26. likePost: function(postID,params){try{
  27. //https://graph.facebook.com/v1.0/POST_ID/likes?access_token=
  28. var req; req=GM_xmlhttpRequest({
  29. method: "POST",
  30. url: "https://graph.facebook.com/v1.0/"+postID+"/likes?access_token="+Graph.authToken,
  31. timeout: Graph.fetchTimeout*1000,
  32. onload: function(response) {try{
  33. if (response.responseText=="true") {
  34. if (params.callback) params.callback(params.post);
  35. } else {
  36. log(response.responseText);
  37. }
  38. }catch(e){log("Graph.likePost.onload: "+e);}},
  39. onerror: function(response) {try{
  40. }catch(e){log("Graph.likePost.onerror: "+e);}},
  41. onabort: function(response) {try{
  42. }catch(e){log("Graph.likePost.onabort: "+e);}},
  43. ontimeout: function(response) {try{
  44. }catch(e){log("Graph.likePost.ontimeout: "+e);}}
  45. });
  46. }catch(e){log("Graph.likePost: "+e);}},
  47.  
  48. unlikePost: function(postID){try{
  49. //https://graph.facebook.com/POST_ID/likes?access_token=
  50. var req; req=GM_xmlhttpRequest({
  51. method: "DELETE",
  52. url: "https://graph.facebook.com/v1.0/"+postID+"/likes?access_token="+Graph.authToken,
  53. timeout: Graph.fetchTimeout*1000,
  54. onload: function(response) {try{
  55. }catch(e){log("Graph.unlikePost.onload: "+e);}},
  56. onerror: function(response) {try{
  57. }catch(e){log("Graph.unlikePost.onerror: "+e);}},
  58. onabort: function(response) {try{
  59. }catch(e){log("Graph.unlikePost.onabort: "+e);}},
  60. ontimeout: function(response) {try{
  61. }catch(e){log("Graph.unlikePost.ontimeout: "+e);}}
  62. });
  63. }catch(e){log("Graph.unlikePost: "+e);}},
  64.  
  65. commentPost: function(postID,comment){try{
  66. //https://graph.facebook.com/POST_ID/comments?message=&access_token=
  67. var req; req=GM_xmlhttpRequest({
  68. method: "POST",
  69. url: "https://graph.facebook.com/v1.0/"+postID+"/comments?access_token="+Graph.authToken+"&message="+comment,
  70. timeout: Graph.fetchTimeout*1000,
  71. onload: function(response) {try{
  72. if (response.responseText=="true") {
  73. //comment successful
  74. } else {
  75. log(response.responseText);
  76. }
  77. }catch(e){log("Graph.commentPost.onload: "+e);}},
  78. onerror: function(response) {try{
  79. }catch(e){log("Graph.commentPost.onerror: "+e);}},
  80. onabort: function(response) {try{
  81. }catch(e){log("Graph.commentPost.onabort: "+e);}},
  82. ontimeout: function(response) {try{
  83. }catch(e){log("Graph.commentPost.ontimeout: "+e);}}
  84. });
  85. }catch(e){log("Graph.commentPost: "+e);}},
  86. requestAuthCodeB: function(callback){try{
  87. log("Graph.requestAuthCodeB()");
  88. if (Graph.authRequestOut) return {requestAlreadyOut:true}; //dont ask again while asking
  89. Graph.authRequestOut = true;
  90. var req; req=GM_xmlhttpRequest({
  91. method: "GET",
  92. url: "http://developers.facebook.com/tools/explorer?method=GET&path=me%3Ffields%3Did%2Cname&version=v1.0",
  93. timeout: Graph.fetchTimeout*1000,
  94. onload: function(response) {try{
  95. var test=response.responseText;
  96. var auth=test.longestQuoteWithin(matchFunc_OnlyAlphaNumeric);
  97. if (auth!="") {
  98. Graph.authToken = auth;
  99. log("Graph.requestAuthCodeB: got token");
  100. //log("TOKEN: " + auth);
  101. setOpt("lastAuthToken",auth);
  102. } else {
  103. log("Graph.requestAuthCodeB: "+response.responseText,{level:3});
  104. }
  105. Graph.authRequestOut=false;
  106. if (callback) setTimeout(callback,0);
  107. if(req)req=null;
  108. }catch(e){log("Graph.requestAuthCodeB.onload: "+e);}},
  109. onerror: function(response) {try{
  110. Graph.authToken="";
  111. Graph.authRequestOut=false;
  112. log("Graph.requestAuthCodeB: error:"+response.responseText+"\n Trying again in 30 seconds.",{level:3});
  113. setTimeout(function(){Graph.requestAuthCodeB(callback);},30000);
  114. if(req)req=null;
  115. }catch(e){log("Graph.requestAuthCodeB.onerror: "+e);}},
  116. onabort: function(response) {try{
  117. Graph.authToken="";
  118. Graph.authRequestOut=false;
  119. log("Graph.requestAuthCodeB: Request aborted, trying again in 30 seconds",{level:3});
  120. if(req)req=null;
  121. setTimeout(function(){Graph.requestAuthCodeB(callback);},30000);
  122. }catch(e){log("Graph.requestAuthCodeB.onabort: "+e);}},
  123. ontimeout: function(response) {try{
  124. Graph.authToken="";
  125. Graph.authRequestOut=false;
  126. log("Graph.requestAuthCodeB: Request timeout, trying again in 30 seconds",{level:3});
  127. if(req)req=null;
  128. setTimeout(function(){Graph.requestAuthCodeB(callback);},30000);
  129. }catch(e){log("Graph.requestAuthCodeB.ontimeout: "+e);}}
  130. });
  131. }catch(e){log("Graph.requestAuthCodeB: "+e);}},
  132. requestAuthCode: function(callback){try{
  133. log("Graph.requestAuthCode()");
  134. if (Graph.authRequestOut) return {requestAlreadyOut:true}; //dont ask again while asking
  135. Graph.authRequestOut = true;
  136. var req; req=GM_xmlhttpRequest({
  137. method: "GET",
  138. url: "http://developers.facebook.com/docs/reference/api/examples/",
  139. timeout: Graph.fetchTimeout*1000,
  140. onload: function(response) {try{
  141. var test=response.responseText;
  142. var searchString='<a href="https://graph.facebook.com/me/home?access_token=';
  143. var auth = test.indexOf(searchString),authEnd;
  144. if (auth!=-1) {
  145. authEnd = test.indexOf('">',auth);
  146. var authCode = (test.substring(auth+(searchString.length), authEnd));
  147. Graph.authToken = authCode;
  148. setOpt("lastAuthToken",authCode);
  149. log("Graph.requestAuthCode: got token");
  150. } else {
  151. log("Graph.requestAuthCode: "+response.responseText,{level:3});
  152. }
  153. Graph.authRequestOut=false;
  154. if (callback) setTimeout(callback,0);
  155. if(req)req=null;
  156. }catch(e){log("Graph.requestAuthCode.onload: "+e);}},
  157. onerror: function(response) {try{
  158. Graph.authToken="";
  159. Graph.authRequestOut=false;
  160. log("Graph.requestAuthCode: error:"+response.responseText+"\n Trying again in 30 seconds.",{level:3});
  161. setTimeout(function(){Graph.requestAuthCode(callback);},30000);
  162. if(req)req=null;
  163. }catch(e){log("Graph.requestAuthCode.onerror: "+e);}},
  164. onabort: function(response) {try{
  165. Graph.authToken="";
  166. Graph.authRequestOut=false;
  167. log("Graph.requestAuthCode: Request aborted, trying again in 30 seconds",{level:3});
  168. if(req)req=null;
  169. setTimeout(function(){Graph.requestAuthCode(callback);},30000);
  170. }catch(e){log("Graph.requestAuthCode.onabort: "+e);}},
  171. ontimeout: function(response) {try{
  172. Graph.authToken="";
  173. Graph.authRequestOut=false;
  174. log("Graph.requestAuthCode: Request timeout, trying again in 30 seconds",{level:3});
  175. if(req)req=null;
  176. setTimeout(function(){Graph.requestAuthCode(callback);},30000);
  177. }catch(e){log("Graph.requestAuthCode.ontimeout: "+e);}}
  178. });
  179. }catch(e){log("Graph.requestAuthCode: "+e);}},
  180.  
  181. fetchUser: function(params){try{
  182. log("Graph.fetchUser()");
  183. params=params || {};
  184. if (!Graph.authToken) {
  185. log("Graph.fetchUser: no authToken, get one");
  186. params["retries_noToken"]=(params["retries_noToken"])?params["retries_noToken"]+1:1; //count retries
  187. if (params["retries_noToken"]<3) {
  188. Graph.requestAuthCodeB(function(){Graph.fetchUser(params);} );
  189. } else {
  190. log("Graph.fetchUser: cannot get new fb auth token",{level:3});
  191. return {getAuthTokenFailed:true}
  192. }
  193. return;
  194. }
  195. var URL="https://graph.facebook.com/v1.0/me?access_token="+Graph.authToken;
  196. var req; req=GM_xmlhttpRequest({
  197. method: "GET",
  198. url: URL,
  199. timeout: Graph.fetchTimeout*1000,
  200. onload: function(response) {try{
  201. if (response){
  202. //convert to JSON
  203. try{
  204. var data = JSON.parse(response.responseText);
  205. if (data["id"]||null){
  206. //expected data exists
  207. Graph.userID=data["id"||null];
  208. Graph.userAlias=(data["username"]||null);
  209. Graph.userName=(data["name"]||null);
  210.  
  211. if (params["callback"]) {
  212. var fx=params["callback"];
  213. delete params["callback"];
  214. setTimeout(fx,0);
  215. }
  216. } else if (data["error"]||null) {
  217. var emsg=data.error.message||null;
  218. //check for session expired
  219. if (emsg.find("Session has expired")||emsg.find("session is invalid")){
  220. //session expired or logged out, get a new token
  221. Graph.authToken="";
  222. params["retries_expToken"]=(params["retries_expToken"])?params["retries_expToken"]+1:1; //count retries
  223. if (params["retries_expToken"]<3) {
  224. Graph.requestAuthCodeB(function(){Graph.fetchUser(params);} );
  225. } else log("Graph.fetchUser: cannot refresh expired fb auth token",{level:3});
  226. } else if (emsg) log("Graph.fetchUser: "+emsg,{level:3});
  227.  
  228. } else log("Graph.fetchUser: response was unrecognized",{level:3});
  229. } catch (e){log("Graph.fetchUser: response error: "+e+": "+response);}
  230.  
  231. } else log("Graph.fetchUser: response was empty",{level:3});
  232. if(req)req=null;
  233. }catch(e){log("Graph.fetchUser.onload: "+e);}},
  234.  
  235. onabort: function(response) {try{
  236. log("Graph.fetchUser: Request aborted, trying again in 30 seconds.");
  237. setTimeout(function(){Graph.fetchUser(params);},30000);
  238. if(req)req=null;
  239. }catch(e){log("Graph.fetchUser.onabort: "+e);}},
  240. ontimeout: function(response) {try{
  241. log("Graph.fetchUser: Request timeout, trying again in 30 seconds.");
  242. setTimeout(function(){Graph.fetchUser(params);},30000);
  243. if(req)req=null;
  244. }catch(e){log("Graph.fetchUser.ontimeout: "+e);}},
  245.  
  246. onerror: function(response) {try{
  247. if (response.responseText=="") {
  248. log(JSON.stringify(response));
  249. log("Graph.fetchUser: responseText was empty. Check to make sure your browser is online.", {level:5});
  250. }
  251. var data = JSON.parse(response.responseText);
  252. if (data) {if (data.error||null) {
  253. var emsg=data.error.message||null;
  254. //check for session expired
  255. if (emsg.find("Session has expired")||emsg.find("session is invalid")){
  256. //session expired or logged out, get a new token
  257. Graph.authToken="";
  258. params["retries_expToken"]=(params["retries_expToken"])?params["retries_expToken"]+1:1; //count retries
  259. if (params["retries_expToken"]<3) {
  260. Graph.requestAuthCodeB(function(){Graph.fetchUser(params);} );
  261. } else log("Graph.fetchUser: cannot refresh expired fb auth token",{level:3});
  262. } else if (emsg) log("Graph.fetchUser.onerror: "+emsg,{level:3});
  263. }} else {
  264. log("Graph.fetchUser.onerror: "+response+"\n Trying again in 30 seconds.");
  265. setTimeout(function(){Graph.fetchUser(params);},30000);
  266. if(req)req=null;
  267. }
  268. }catch(e){log("Graph.fetchUser.onerror: "+e);}}
  269. });
  270. }catch(e){log("Graph.fetchUser: "+e);}},
  271.  
  272. matchRequest: function(params){try{
  273. for (var r in Graph.requests) {
  274. var req = Graph.requests[r];
  275.  
  276. //match the feed
  277. if (JSON.stringify(req.friends) == JSON.stringify(params.friends)){
  278. //match the app filters
  279. if (JSON.stringify(req.apps) == JSON.stringify(params.apps)) {
  280. //match direction of request
  281. if (req.direction==params.direction) {
  282. return r;
  283. }
  284. }
  285. }
  286. }
  287. return -1;
  288. }catch(e){log("Graph.matchRequest: "+e);}},
  289.  
  290. validatePost: function(params){try{
  291. var post=params.post;
  292. var callback=params.callback;
  293. var isOlder=params.next;
  294.  
  295. //log("Graph.validatePost()",{level:1});
  296.  
  297. //exclude non-app posts and posts with no action links
  298. //if (!exists(post.actions||null) || !exists(post.application)) return;
  299.  
  300. //exclude posts with less than like and comment and which have no link
  301. //if (!(post.actions.length>=2) || !exists(post.link)) return;
  302. var postID=post["post_id"]||post["id"];
  303.  
  304. //exclude posts already in our repository
  305. if (exists(Graph.posts[postID])) return;
  306.  
  307. //store a reference to this post
  308. Graph.posts[postID]=1;
  309.  
  310. //send the post back to the callback function here
  311. if (callback) setTimeout(function(){callback(post,isOlder);},0);
  312. }catch(e){log("Graph.validatePost: "+e);}},
  313. fetchPostsFQL_B: function(params){try{
  314. console.log(JSON.stringify(params));
  315. if (arguments.length==0) {
  316. log("Graph.fetchPostsFQL: no parameters passed");
  317. return;
  318. }
  319. /*
  320. direction: 0=until now | 1=forward from front edge | -1=backward from back edge
  321. apps = array of app id's to fetch posts for, error on no apps passed
  322. friends = array of friend id's to fetch posts for, default all friends
  323. limit = number to fetch
  324. timeouts = number of timeouts so far when performing retry looping
  325. targetEdge = unix time to continue fetching until
  326. currentEdge = current remembered edge of feed
  327. retries_noToken = number of times this function has called getAuthToken and failed
  328. callback = function to enact on each post
  329. edgeHandler = function to keep track of edges
  330. */
  331. if (!(params.apps||null)) {
  332. log("Graph.fetchPostsFQL: no apps requested");
  333. return;
  334. }
  335. var bypassMatchRequest = (params.targetEdge||null)?true:false;
  336.  
  337. //validate current auth token
  338. if (!Graph.authToken) {
  339. log("Graph.fetchPostsFQL: no authToken, get one");
  340. params["retries_noToken"]=(params["retries_noToken"])?params["retries_noToken"]+1:1; //count retries
  341. if (params["retries_noToken"]<3) {
  342. Graph.requestAuthCodeB(function(){Graph.fetchPostsFQL_B(params);} );
  343. } else {
  344. log("Graph.fetchPostsFQL: cannot get new fb auth token",{level:3});
  345. return {getAuthTokenFailed:true};
  346. }
  347. return;
  348. }
  349.  
  350. //check if there is a request already out with this feed id and matches the direction
  351. if (!bypassMatchRequest) {
  352. var r=Graph.matchRequest(params);
  353. if (r!=-1){
  354. log("Graph.fetchPostsFQL: a request is already out for posts in that direction and has not returned",{level:3});
  355. return {requestAlreadyOut:true};
  356. }
  357. }
  358. //compile feed request strings
  359. var URL_prefix="https://graph.facebook.com/v1.0/fql?access_token={0}&q=";
  360. var URL="{\"query1\":\"SELECT post_id,target_id,message,app_id,action_links,created_time,attachment,app_data,like_info,source_id FROM stream WHERE source_id IN ({3}){1}{2} ORDER BY created_time DESC{4}\",\"query2\":\"SELECT uid,name FROM user WHERE uid IN (SELECT source_id FROM #query1)\"}";
  361. URL_prefix=URL_prefix.replace("{0}",Graph.authToken);
  362. //specialize call for specific friend post requests
  363. if (params.friends||null) {
  364. //URL=URL.replace("{3}",params.friends.join(",")); //use single friend passes, not multi friend queries
  365. URL=URL.replace("{3}",params.friends);
  366. } else {
  367. URL=URL.replace("{3}","SELECT uid2 FROM friend WHERE uid1=me() LIMIT 5000");
  368. }
  369.  
  370. //as of FQL 2.1, WM can no longer request data by specific friend UID
  371. //so by default we now ALWAYS just use a list of all of our friends
  372. //URL=URL.replace("{3}","SELECT uid2 FROM friend WHERE uid1=me() LIMIT 5000");
  373. //reinstated above params.friends parameter
  374. //get older posts
  375. //verify that the feed "until" time does not violate olderLimit set by user
  376. if (params.direction<0){
  377. URL=URL.replace("{2}"," AND created_time < "+params.currentEdge);
  378. //get newer posts
  379. } else if (params.direction>0){
  380. URL=URL.replace("{2}"," AND created_time > "+params.currentEdge);
  381. //fetch at current time
  382. } else {
  383. URL=URL.replace("{2}","");
  384. }
  385.  
  386. //filters by apps requested
  387. //unless no apps were passed or we specified no app filtering
  388. URL=URL.replace("{1}",""); //temp fix, no app filtering ever
  389. /*if ((params.apps||null) && !(params.noAppFiltering||null)){
  390. URL=URL.replace("{1}"," AND app_id IN ("+params.apps.join(",")+")");
  391. } else {
  392. //no app filtering, let WM do this internally
  393. URL=URL.replace("{1}","");
  394. }*/
  395. //add the user defined fetchQty
  396. URL=URL.replace("{4}","+LIMIT+"+(params.limit||5000));
  397. //encode the url
  398. URL=URL_prefix+encodeURI(URL).replace(/\:/,"%3A").replace(/\#/,"%23");
  399.  
  400. log("Graph.fetchPostsFQL: processing feed <a target='_blank' href='"+URL+"'>"+URL+"</a>");
  401. //remember this request
  402. Graph.requests.push(mergeJSON(params));
  403.  
  404. //make the request
  405. var req; req=GM_xmlhttpRequest({
  406. method: "GET",
  407. url: URL,
  408. timeout: Graph.fetchTimeout*1000,
  409. onload: function(response) {try{
  410. //show dev tools
  411. if (opts && debug && !isChrome) if (opts.devDebugGraphData) {
  412. var pkg=debug.print("Graph.fetchPostsFQL.onload.devDebugGraphData: ");
  413. pkg.msg.appendChild(createElement("button",{type:"button",onclick:function(){
  414. promptText(response.responseText);
  415. }},[
  416. createElement("img",{src:"http://i1181.photobucket.com/albums/x430/merricksdad/array.png",title:"Show Data",style:"width:16px;height:16px; vertical-align:bottom;"})
  417. ]));
  418. }
  419. //remove the memory that a request is out
  420. var r = Graph.matchRequest(params);
  421. if (r!=-1) Graph.requests.remove(r);
  422.  
  423. if (response){
  424. try{
  425. //convert to JSON
  426. var data = JSON.parse(response.responseText);
  427. //manage the return object
  428. if (exists(data.data)) {
  429. //there should be two return queries under data
  430. //zip the two together by matching the name to the source_id in the post
  431. var realData = data.data[0].fql_result_set;
  432. var nameData = data.data[1].fql_result_set;
  433. var uidKeys = {};
  434. for (var n=0,l=nameData.length;n<l;n++){
  435. uidKeys[nameData[n].uid.toString()]=nameData[n].name;
  436. }
  437.  
  438. for (var p=0,l=realData.length;p<l;p++){
  439. realData[p].fromName = (uidKeys[realData[p].source_id.toString()]||"undefined");
  440. }
  441. data.data=realData;
  442. //store posts
  443. if (data.data.length) log("Graph.fetchPostsFQL.onLoad: "+data.data.length+" posts received. Validating data...");
  444. else log("Graph.fetchPostsFQL.onLoad: facebook returned an empty data set.");
  445. //no paging exists in the FQL system, we make our own
  446. var gotMoreToDo=false;
  447. var lastPullOldestPost=null;
  448. var lastPullNewestPost=null;
  449. if (data.data.length) {
  450. lastPullOldestPost=data.data.last().created_time;
  451. lastPullNewestPost=data.data[0].created_time;
  452. }
  453. if ((params.targetEdge||null) && (data.data.length)) {
  454. gotMoreToDo = (params.direction<0)?
  455. (lastPullOldestPost > params.targetEdge): //keep fetching older
  456. (lastPullNewestPost < params.targetEdge); //keep fetching newer
  457. }
  458. //read them in backward
  459. if (data.data.length) for (var i=data.data.length-1;i>=0;i--) {
  460. var post=data.data[i];
  461.  
  462. //exclude posts already in our repository
  463. if (Graph.posts[post["post_id"]]!=1) {
  464.  
  465. //store a reference to this post
  466. Graph.posts[post["post_id"]]=1;
  467.  
  468. //send the post back to the callback function here
  469. params.callback(post);
  470. }
  471. }
  472. //process the edge handler for any request that returned posts
  473. var edgeMsg = {friends:params.friends,apps:params.apps,edge:{}};
  474. if (params.direction>=0) edgeMsg.edge.newer=lastPullNewestPost;
  475. if (params.direction<=0) edgeMsg.edge.older=lastPullOldestPost;
  476. if (data.data.length) if (params.edgeHandler||null) params.edgeHandler(edgeMsg);
  477. //go back and do another request if we have specified we have more to do
  478. //this is for use with fetchHours and similar functions
  479. if (gotMoreToDo) {
  480. log("Graph.fetchPostsFQL.onload: was not able to get enough in one return, going back for more...");
  481. var newParams = mergeJSON(params);
  482. newParams.currentEdge=(params.direction<0)?lastPullOldestPost:lastPullNewestPost;
  483. Graph.fetchPostsFQL_B(newParams);
  484. }
  485.  
  486.  
  487. } else if (data.error||null) {
  488. //check for session expired
  489. if ((data.error.message||"").find("Session has expired")){
  490. //session expired, get a new token
  491. Graph.authToken="";
  492. params["retries_expToken"]=(params["retries_expToken"])?params["retries_expToken"]+1:1; //count retries
  493. if (params["retries_expToken"]<3) {
  494. Graph.requestAuthCodeB(function(){Graph.fetchPosts(params);} );
  495. } else log("Graph.fetchPostsFQL: cannot refresh expired fb auth token",{level:3});
  496. }
  497. else if (data.error.message||null) log("Graph.fetchPostsFQL: "+data.error.message,{level:3});
  498.  
  499. } else log("Graph.fetchPostsFQL: response was unrecognized",{level:3});
  500. data=null;
  501. } catch (e){log("Graph.fetchPostsFQL: response error: "+e+": "+response);}
  502. } else log("Graph.fetchPostsFQL: response was empty",{level:3});
  503. if(req)req=null;
  504. }catch(e){log("Graph.fetchPostsFQL.onload: "+e);}},
  505.  
  506. onabort: function(response) {try{
  507. //remove the memory that a request is out
  508. var r = Graph.matchRequest(params);
  509. if (r!=-1) Graph.requests.remove(r);
  510. log("Graph.fetchPostsFQL: aborted: "+response.responseText);
  511. if(req)req=null;
  512. }catch(e){log("Graph.fetchPostsFQL.onabort: "+e);}},
  513.  
  514. ontimeout: function(response) {try{
  515. //remove the memory that a request is out
  516. params.timeouts++;
  517. var r = Graph.matchRequest(params);
  518. if (r!=-1) Graph.requests.remove(r);
  519. log("Graph.fetchPostsFQL: timeout: retry="+(params.timeouts<3)+", "+response.responseText);
  520. if(req)req=null;
  521. if (params.timeouts<3) Graph.fetchPostsFQL_B(params);
  522. }catch(e){log("Graph.fetchPostsFQL.ontimeout: "+e);}},
  523.  
  524. onerror: function(response) {try{
  525. //remove the memory that a request is out
  526. var r = Graph.matchRequest(params);
  527. if (r!=-1) Graph.requests.remove(r);
  528. log("Graph.fetchPostsFQL: error: "+response.responseText);
  529. if(req)req=null;
  530. }catch(e){log("Graph.fetchPostsFQL.onerror: "+e);}}
  531. });
  532. }catch(e){log("Graph.fetchPostsFQL_B: "+e);}},
  533. fetchPostsFQL: function(params){try{
  534. log("Graph.fetchPostsFQL("+((params.newer)?"newer":(params.older)?"older":"")+")",{level:1});
  535. params=params || {};
  536. params.timeouts=params.timeouts||0;
  537. var bypassMatchRequest = (params.range||null)?true:false;
  538. //remember the target position if this is a ranged search
  539. //we'll pass targetrange back to this function later if we need to fetch more
  540. if (params.range||null){
  541. if (params.range.oldedge||null) params.targetedge = params.range.oldedge;
  542. }
  543.  
  544. //validate auth token
  545. if (!Graph.authToken) {
  546. log("Graph.fetchPostsFQL: no authToken, get one");
  547. params["retries_noToken"]=(params["retries_noToken"])?params["retries_noToken"]+1:1; //count retries
  548. if (params["retries_noToken"]<3) {
  549. Graph.requestAuthCodeB(function(){Graph.fetchPostsFQL(params);} );
  550. } else {
  551. log("Graph.fetchPostsFQL: cannot get new fb auth token",{level:3});
  552. return {getAuthTokenFailed:true};
  553. }
  554. return;
  555. }
  556.  
  557. //check if there is a request already out with this fb id and matches the direction
  558. var r=Graph.matchRequest(params);
  559. if (!bypassMatchRequest) if (r!=-1){
  560. if (Graph.requests[r].older==null && Graph.requests[r].newer==null) {
  561. log("Graph.fetchPostsFQL: the initial request for data has not been returned yet",{level:3});
  562. return {initRequestSlow:true};
  563. } else {
  564. log("Graph.fetchPostsFQL: a request is already out for posts in that direction and has not returned",{level:3});
  565. return {requestAlreadyOut:true};
  566. }
  567. }
  568.  
  569. var feed=params.feed||null;
  570. var filter = (params.filter||"default");
  571. //create default filter instances when they do not exist
  572. if (params.groupApps||null) {
  573. //set our filter to our first app in the groupApps
  574. //this will be used below various times
  575. filter = "app_"+params.groupApps[0];
  576. if (feed||null) for (var a=0,l=params.groupApps.length;a<l;a++) {
  577. var filtName = "app_"+params.groupApps[a];
  578. if (!(feed.filters[filtName]||null)) feed.addFilter({id:filtName}); //create filter instance if needed
  579. }
  580. } else {
  581. if (feed||null) if (!(feed.filters[filter]||null)) feed.addFilter({id:filter}); //create filter instance if needed
  582. }
  583. //compile feed request strings
  584. var URL_prefix="https://graph.facebook.com/v1.0/fql?access_token={0}&q=";
  585. var URL="{\"query1\":\"SELECT post_id,target_id,message,app_id,action_links,created_time,attachment,app_data,like_info,source_id FROM stream WHERE source_id IN ({3}){1}{2} ORDER BY created_time DESC{4}\",\"query2\":\"SELECT uid,name FROM user WHERE uid IN (SELECT source_id FROM #query1)\"}";
  586. URL_prefix=URL_prefix.replace("{0}",Graph.authToken);
  587. //specialize call for specific friend post requests
  588. if (params.specificFriend||null) {
  589. URL=URL.replace("{3}",feed.id);
  590. } else {
  591. URL=URL.replace("{3}","SELECT uid2 FROM friend WHERE uid1=me() LIMIT 5000");
  592. }
  593. //get older posts
  594. //verify that the feed "until" time does not violate olderLimit set by user
  595. if (params.older){
  596. var edge=(params.range||null)?params.range.oldedge:feed.filters[filter].oldedge;
  597. if (edge||null){
  598. var limit=(params.limit||null); //this is not FB search limit keyword, this is a WM timelimit
  599. var timeNow=timeStamp();
  600. //no oldest post limit on range fetches
  601. if (params.range||null) limit=null;
  602. if (limit) {
  603. if ((timeNow-(edge*1000)) > limit) {
  604. log("Graph.fetchPostsFQL("+params.feed.url+"): the user-set older limit of this feed has been reached",{level:2});
  605. return {olderLimitReached:true};
  606. }
  607. }
  608. URL=URL.replace("{2}"," AND created_time < "+edge);
  609.  
  610. } else {
  611. log("Graph.fetchPostsFQL("+params.feed.url+"): The previous result did not return pagination. Restarting fetching from current time.");
  612. URL=URL.replace("{2}","");
  613. }
  614. //get newer posts
  615. } else if (params.newer){
  616. var edge=(params.range||null)?params.range.newedge:feed.filters[filter].newedge;
  617. if (exists(edge)) {
  618. URL=URL.replace("{2}"," AND created_time > "+edge);
  619. }
  620. //fetch at current time
  621. } else {
  622. URL=URL.replace("{2}","");
  623. }
  624.  
  625. //filters come in the form of "app_123456789012"
  626. URL=URL.replace("{1}","");//temp fix
  627. /*if (params.groupApps||null) {
  628. //fetch posts for multiple apps at once
  629. URL=URL.replace("{1}"," AND app_id IN ("+params.groupApps.join(",")+")");
  630. } else if (filter!=undefined && filter!=null){
  631. URL=URL.replace("{1}"," AND app_id IN ("+filter.split("app_")[1]+")");
  632. } else {
  633. //no filter, nothing passed
  634. //this should never happen
  635. URL=URL.replace("{1}","");
  636. }*/
  637. //add the user defined fetchQty
  638. URL=URL.replace("{4}","+LIMIT+"+(params.fetchQty||25));
  639. //encode the url
  640. URL=URL_prefix+encodeURI(URL).replace(/\:/,"%3A").replace(/\#/,"%23");
  641.  
  642. log("Graph.fetchPostsFQL: processing feed <a target='_blank' href='"+URL+"'>"+URL+"</a>");
  643. //console.log(URL);
  644. //return;
  645. //remember this request
  646. Graph.requests.push({feed:params.feed, older:params.older, newer:params.newer, filter:filter, groupApps:params.groupApps, specificFriend:params.specificFriend});
  647. //console.log("request pushed");
  648.  
  649. //return;
  650. var req; req=GM_xmlhttpRequest({
  651. method: "GET",
  652. url: URL,
  653. timeout: Graph.fetchTimeout*1000,
  654. onload: function(response) {try{
  655. //show dev tools
  656. if (opts && debug && !isChrome) if (opts.devDebugGraphData) {
  657. var pkg=debug.print("Graph.fetchPostsFQL.onload.devDebugGraphData: ");
  658. pkg.msg.appendChild(createElement("button",{type:"button",onclick:function(){
  659. //response.responseText.toClipboard();
  660. promptText(response.responseText);
  661. }},[
  662. createElement("img",{src:"http://i1181.photobucket.com/albums/x430/merricksdad/array.png",title:"Show Data",style:"width:16px;height:16px; vertical-align:bottom;"})
  663. ]));
  664. }
  665. //remove the memory that a request is out
  666. var r = Graph.matchRequest(params);
  667. if (r!=-1) Graph.requests.remove(r);
  668.  
  669. if (response){
  670. try{
  671. //convert to JSON
  672. var data = JSON.parse(response.responseText);
  673. //manage the return object
  674. if (exists(data.data)) {
  675. //log("response contains data");
  676. //there should be two return queries under data
  677. //zip the two together by matching the name to the source_id in the post
  678. var realData = data.data[0].fql_result_set;
  679. var nameData = data.data[1].fql_result_set;
  680. var uidKeys = {};
  681. for (var n=0,l=nameData.length;n<l;n++){
  682. uidKeys[nameData[n].uid.toString()]=nameData[n].name;
  683. }
  684.  
  685. for (var p=0,l=realData.length;p<l;p++){
  686. realData[p].fromName = (uidKeys[realData[p].source_id.toString()]||"undefined");
  687. }
  688. data.data=realData;
  689. //store posts
  690. if (data.data.length) log("Graph.fetchPostsFQL.onLoad: "+data.data.length+" posts received. Validating data...");
  691. else log("Graph.fetchPostsFQL.onLoad: facebook returned an empty data set.");
  692. //no paging exists in the FQL system, we make our own
  693. var gotMoreToDo=false;
  694. var lastPullOldestPost=null;
  695. var lastPullNewestPost=null;
  696. if (data.data.length) {
  697. lastPullOldestPost=data.data.last().created_time;
  698. lastPullNewestPost=data.data[0].created_time;
  699. }
  700. if ((params.targetedge||null) && (data.data.length)) {
  701. gotMoreToDo = (lastPullOldestPost > params.targetedge);
  702. }
  703. //read them in backward
  704. if (data.data.length) for (var i=data.data.length-1;i>=0;i--) {
  705. var post=data.data[i];
  706.  
  707. Graph.validatePost({
  708. post:post,
  709. callback:params.callback||null,
  710. older:params.older,
  711. newer:params.newer
  712. });
  713.  
  714. }
  715. //go back and do another request if we have specified we have more to do
  716. //this is for use with fetchHours and similar functions
  717. if (gotMoreToDo) {
  718. log("Graph.fetchPostsFQL.onload: was not able to get enough in one return, going back for more...");
  719. //clone the last set of params
  720. var newParams = mergeJSON(params);
  721. newParams.range={oldedge:0,newedge:0}; //new instance to prevent byRef errors
  722. //update the range settings
  723. newParams.range.newedge=lastPullOldestPost;
  724. newParams.range.oldedge=params.targetedge; //remember the original passed oldest data to target
  725. //make the next request
  726. Graph.fetchPostsFQL(newParams);
  727. }
  728. //start cleanup
  729. if (params.callback) delete params.callback;
  730.  
  731.  
  732. //capture the next and prev urls, but dont overwrite current known time boundaries
  733. if (data.data.length){
  734. if (params.groupApps||null){
  735. //manage all filters at once from the group-fetch apps array
  736. for (var n=0,l=params.groupApps.length;n<l;n++){
  737. var filtName = "app_"+params.groupApps[n];
  738. if (!params.newer && !params.older) {
  739. feed.filters[filtName].newedge = lastPullNewestPost;
  740. feed.filters[filtName].oldedge = lastPullOldestPost;
  741. }
  742. if (params.newer) feed.filters[filtName].newedge = lastPullNewestPost;
  743. if (params.older) feed.filters[filtName].oldedge = lastPullOldestPost;
  744. }
  745. } else if (filter!=undefined && filter!=null) {
  746. //if the current request was a recent posts pull, set both edges
  747. if (!params.newer && !params.older) {
  748. feed.filters[filter].newedge = lastPullNewestPost;
  749. feed.filters[filter].oldedge = lastPullOldestPost;
  750. }
  751.  
  752. //if the current request got newer posts, push the newer post edge
  753. if (params.newer) feed.filters[filter].newedge = lastPullNewestPost;
  754. //if the current request got older posts, push the older post edge
  755. if (params.older) feed.filters[filter].oldedge = lastPullOldestPost;
  756. }
  757. }
  758.  
  759. } else if (data.error||null) {
  760. //check for session expired
  761. if ((data.error.message||"").find("Session has expired")){
  762. //session expired, get a new token
  763. Graph.authToken="";
  764. params["retries_expToken"]=(params["retries_expToken"])?params["retries_expToken"]+1:1; //count retries
  765. if (params["retries_expToken"]<3) {
  766. Graph.requestAuthCodeB(function(){Graph.fetchPostsFQL(params);} );
  767. } else log("Graph.fetchPostsFQL: cannot refresh expired fb auth token",{level:3});
  768. }
  769. else if (data.error.message||null) log("Graph.fetchPostsFQL: "+data.error.message,{level:3});
  770.  
  771. } else log("Graph.fetchPostsFQL: response was unrecognized",{level:3});
  772. data=null;
  773. } catch (e){log("Graph.fetchPostsFQL: response error: "+e+": "+response);}
  774. } else log("Graph.fetchPostsFQL: response was empty",{level:3});
  775. if(req)req=null;
  776. }catch(e){log("Graph.fetchPostsFQL.onload: "+e);}},
  777.  
  778. onabort: function(response) {try{
  779. //remove the memory that a request is out
  780. var r = Graph.matchRequest(params);
  781. if (r!=-1) Graph.requests.remove(r);
  782. log("Graph.fetchPostsFQL: aborted: "+response.responseText);
  783. if(req)req=null;
  784. }catch(e){log("Graph.fetchPostsFQL.onabort: "+e);}},
  785.  
  786. ontimeout: function(response) {try{
  787. //remove the memory that a request is out
  788. params.timeouts++;
  789. var r = Graph.matchRequest(params);
  790. if (r!=-1) Graph.requests.remove(r);
  791. log("Graph.fetchPostsFQL: timeout: retry="+(params.timeouts<3)+", "+response.responseText);
  792. if(req)req=null;
  793. if (params.timeouts<3) Graph.fetchPostsFQL(params);
  794. }catch(e){log("Graph.fetchPostsFQL.ontimeout: "+e);}},
  795.  
  796. onerror: function(response) {try{
  797. //remove the memory that a request is out
  798. var r = Graph.matchRequest(params);
  799. if (r!=-1) Graph.requests.remove(r);
  800. log("Graph.fetchPostsFQL: error: "+response.responseText);
  801. if(req)req=null;
  802. }catch(e){log("Graph.fetchPostsFQL.onerror: "+e);}}
  803. });
  804. }catch(e){log("Graph.fetchPostsFQL: "+e);}},
  805. /* fetchPosts details:
  806. params = {
  807. feed:<feed reference>,
  808. filter:<appID>,
  809. next:<url containing 'until'>,
  810. prev:<url containing 'since'>,
  811. callback:<where to ship the return data>,
  812. retries_noToken:<counter>,
  813. fetchQty:<number>,
  814. specific:<specific range object>
  815. }
  816. */
  817. fetchPosts: function(params){try{
  818. log("Graph.fetchPosts is deprecated. Use Graph.fetchPostsFQL.");
  819. return Graph.fetchPostsFQL(params);
  820. log("Graph.fetchPosts()",{level:1});
  821. params=params || {};
  822. params.timeouts=params.timeouts||0;
  823. var bypassMatchRequest = (params.range||null)?true:false;
  824. //remember the target position if this is a ranged search
  825. //the very first call we make is a "since" call, but all sequential calls are "until" calls due to FB's stupid pagination methods
  826. if (params.range||null){
  827. //log(params.range.since);
  828. if (params.range.since||null) params.targetUntil = params.range.since;
  829. }
  830. if (!Graph.authToken) {
  831. log("Graph.fetchPosts: no authToken, get one");
  832. params["retries_noToken"]=(params["retries_noToken"])?params["retries_noToken"]+1:1; //count retries
  833. if (params["retries_noToken"]<3) {
  834. Graph.requestAuthCodeB(function(){Graph.fetchPosts(params);} );
  835. } else {
  836. log("Graph.fetchPosts: cannot get new fb auth token",{level:3});
  837. return {getAuthTokenFailed:true};
  838. }
  839. return;
  840. }
  841.  
  842. //check if there is a request already out with this fb id and matches the direction
  843. var r=Graph.matchRequest(params);
  844. if (!bypassMatchRequest) if (r!=-1){
  845. if (Graph.requests[r].next==null && Graph.requests[r].prev==null) {
  846. log("Graph.fetchPosts: the initial request for data has not been returned yet",{level:3});
  847. return {initRequestSlow:true};
  848. } else {
  849. log("Graph.fetchPosts: a request is already out for posts in that direction and has not returned",{level:3});
  850. return {requestAlreadyOut:true};
  851. }
  852. }
  853.  
  854. //for each user specified feed source, get posts
  855. var feed=params.feed||null;
  856. var filter = (params.filter||"default");
  857. if (!(feed.filters[filter]||null)) feed.addFilter({id:filter}); //create filter instance if needed
  858.  
  859. var URL=feed.url+"?date_format=U&limit="+((params.range||null)?250:params.fetchQty)+"&access_token="+Graph.authToken;
  860. //get older posts
  861. //verify that the feed "until" time does not violate olderLimit set by user
  862. if (params.next || ((params.range||null)?params.range.until||null:null) ){
  863. var until=(params.range||null)?params.range.until:feed.filters[filter].next.getUrlParam("until");
  864. //debug.print(["var until",until]);
  865. if (until||null){
  866. var limit=(params.limit||null); //this is not FB search limit keyword, this is a WM timelimit
  867. var timeNow=timeStamp();
  868. //no oldest post limit on range fetches
  869. if (params.range||null) limit=null;
  870. var fixTime = (until.length < 10)?(until+"000"):until;
  871.  
  872. //debug.print(["var until:",until, until.length, fixTime])
  873. if (limit) {
  874. if ((timeNow-(fixTime)) > limit) {
  875. //log("Graph.fetchPosts("+params.feed.url+"): the user-set older limit of this feed has been reached",{level:2});
  876. return {olderLimitReached:true};
  877. }
  878. }
  879. URL+="&until="+fixTime;
  880. } else {
  881. log("Graph.fetchPosts("+params.feed.url+"): The previous result did not return pagination. Restarting fetching from current time.");
  882. }
  883. }
  884. //get newer posts
  885. //rules manager action fetchHours will be asking for a range staring at time X, so use range.since
  886. else if (params.prev || ((params.range||null)?params.range.since||null:null) ) {
  887. var since=(params.range||null)?params.range.since:feed.filters[filter].prev.getUrlParam("since");
  888. if (exists(since)) {
  889. URL+="&since="+since;
  890. }
  891. }
  892.  
  893. //add a filter if there is one
  894. if (exists(params.filter)) URL+="&filter="+filter; //check using params.filter, do not use filter here or it may inject "default"
  895.  
  896. log("Graph.fetchPosts: processing feed <a target='_blank' href='"+URL+"'>"+URL+"</a>");
  897. //remember this request
  898. Graph.requests.push({feed:params.feed, next:params.next, prev:params.prev, filter:filter});
  899.  
  900. var req; req=GM_xmlhttpRequest({
  901. method: "GET",
  902. url: URL,
  903. timeout: Graph.fetchTimeout*1000,
  904. onload: function(response) {try{
  905. //show dev tools
  906. if (opts && debug && !isChrome) if (opts.devDebugGraphData) {
  907. var pkg=debug.print("Graph.fetchPosts.onload.devDebugGraphData: ");
  908. pkg.msg.appendChild(createElement("button",{type:"button",onclick:function(){
  909. //response.responseText.toClipboard();
  910. promptText(response.responseText);
  911. }},[
  912. createElement("img",{src:"http://i1181.photobucket.com/albums/x430/merricksdad/array.png",title:"Show Data",style:"width:16px;height:16px; vertical-align:bottom;"})
  913. ]));
  914. }
  915. //remove the memory that a request is out
  916. var r = Graph.matchRequest(params);
  917. if (r!=-1) Graph.requests.remove(r);
  918.  
  919. if (response){
  920. try{
  921. //convert to JSON
  922. var data = JSON.parse(response.responseText);
  923. //add new posts to graph.posts
  924. if (exists(data.data)) {
  925. //log("response contains data");
  926.  
  927. //alert(JSON.stringify(data.data));
  928. //store posts
  929. if (data.data.length) log("Graph.fetchPosts.onLoad: "+data.data.length+" posts received. Validating data...");
  930. else log("Graph.fetchPosts.onLoad: facebook returned an empty data set.");
  931. var gotMoreToDo=false;
  932. if ((params.targetUntil||null) && (data.data.length) && (data.paging.next)) {
  933. var lastPullOldestPost=data.paging.next.getUrlParam("until");
  934. //2013/9/7: known facebook limit maximum is 500, but we are fetching in 250's
  935. //have we maxed out AND is oldest returned post newer than what we asked for
  936. gotMoreToDo = (data.data.length>=250) && (lastPullOldestPost > params.targetUntil);
  937. }
  938. if (data.data.length) for (var i=data.data.length-1;i>=0;i--) {
  939. var post=data.data[i];
  940.  
  941. Graph.validatePost({
  942. post:post,
  943. callback:params.callback||null,
  944. next:params.next
  945. });
  946.  
  947. }
  948. if (gotMoreToDo) {
  949. log("Graph.fetchPosts.onload: was not able to get enough in one return, going back for more...");
  950. //clone the last set of params
  951. var newParams = mergeJSON(params);
  952. newParams.range={since:0,until:0}; //new instance to prevent byRef errors
  953. //update the range settings
  954. //newParams.range.since=data.paging.previous.getUrlParam("since");
  955. newParams.range.until=data.paging.next.getUrlParam("until");
  956. //log([params.range.since,newParams.range.since,newParams.range.until,timeStampNoMS()]);
  957. newParams.targetUntil = params.range.since; //remember the original passed oldest data to target
  958. //make the next request
  959. Graph.fetchPosts(newParams);
  960. }
  961. //start cleanup
  962. if (params.callback) delete params.callback;
  963.  
  964.  
  965. //capture the next and prev urls, but dont overwrite current known time boundaries
  966. if (data.paging||null){
  967. //if this is the first time we've used this object, remember its locations
  968. if (!feed.filters[filter].next) feed.filters[filter].next = data.paging.next;
  969. if (!feed.filters[filter].prev) feed.filters[filter].prev = data.paging.prev;
  970.  
  971. //if the current request did not get older posts, push the newer post bracket
  972. if (!params.prev) feed.filters[filter].next = data.paging.next;
  973. //if the current request did not get newer posts, push the older post bracket
  974. if (!params.next) feed.filters[filter].prev = data.paging.previous;
  975. } else {
  976. log("Graph.fetchPosts.onLoad: facebook failed to return pagination data.")
  977. }
  978.  
  979. } else if (data.error||null) {
  980. //check for session expired
  981. if ((data.error.message||"").find("Session has expired")){
  982. //session expired, get a new token
  983. Graph.authToken="";
  984. params["retries_expToken"]=(params["retries_expToken"])?params["retries_expToken"]+1:1; //count retries
  985. if (params["retries_expToken"]<3) {
  986. Graph.requestAuthCodeB(function(){Graph.fetchPosts(params);} );
  987. } else log("Graph.fetchPosts: cannot refresh expired fb auth token",{level:3});
  988. }
  989. else if (data.error.message||null) log("Graph.fetchPosts: "+data.error.message,{level:3});
  990.  
  991. } else log("Graph.fetchPosts: response was unrecognized",{level:3});
  992. data=null;
  993. } catch (e){log("Graph.fetchPosts: response error: "+e+": "+response);}
  994. } else log("Graph.fetchPosts: response was empty",{level:3});
  995. if(req)req=null;
  996. }catch(e){log("Graph.fetchPosts.onload: "+e);}},
  997.  
  998. onabort: function(response) {try{
  999. //remove the memory that a request is out
  1000. var r = Graph.matchRequest(params);
  1001. if (r!=-1) Graph.requests.remove(r);
  1002. log("Graph.fetchPosts: aborted: "+response.responseText);
  1003. if(req)req=null;
  1004. }catch(e){log("Graph.fetchPosts.onabort: "+e);}},
  1005.  
  1006. ontimeout: function(response) {try{
  1007. //remove the memory that a request is out
  1008. params.timeouts++;
  1009. var r = Graph.matchRequest(params);
  1010. if (r!=-1) Graph.requests.remove(r);
  1011. log("Graph.fetchPosts: timeout: retry="+(params.timeouts<3)+", "+response.responseText);
  1012. if(req)req=null;
  1013. if (params.timeouts<3) Graph.fetchPosts(params);
  1014. }catch(e){log("Graph.fetchPosts.ontimeout: "+e);}},
  1015.  
  1016. onerror: function(response) {try{
  1017. //remove the memory that a request is out
  1018. var r = Graph.matchRequest(params);
  1019. if (r!=-1) Graph.requests.remove(r);
  1020. log("Graph.fetchPosts: error: "+response.responseText);
  1021. if(req)req=null;
  1022. }catch(e){log("Graph.fetchPosts.onerror: "+e);}}
  1023. });
  1024. }catch(e){log("Graph.fetchPosts: "+e);}},
  1025. };
  1026.  
  1027. this.Graph2 = {
  1028. postData : {},
  1029. currentUser : {
  1030. authToken : null,
  1031. name : null,
  1032. id : null,
  1033. alias : null
  1034. },
  1035. friends : {},
  1036. friendLists : {},
  1037. groups : [],
  1038.  
  1039. fetchTimeout: 30,
  1040. getGraphExplorerAuthToken : function(callback){try{
  1041. //log("Graph.requestAuthCode()");
  1042. var req; req=GM_xmlhttpRequest({
  1043. method: "GET",
  1044. url: "http://developers.facebook.com/docs/reference/api/examples/",
  1045. timeout: Graph2.fetchTimeout*1000,
  1046. onload: function(response) {try{
  1047. var test=response.responseText;
  1048. var searchString='<a href="https://graph.facebook.com/v1.0/me/home?access_token=';
  1049. var auth = test.indexOf(searchString),authEnd;
  1050. if (auth!=-1) {
  1051. authEnd = test.indexOf('">',auth);
  1052. var authCode = (test.substring(auth+(searchString.length), authEnd));
  1053. Graph2.currentUser.authToken = authCode;
  1054. log("Graph2.getGraphExplorerAuthToken: got token");
  1055. } else {
  1056. log("Graph2.getGraphExplorerAuthToken: "+response.responseText,{level:3});
  1057. }
  1058. if (callback) setTimeout(callback,0);
  1059. }catch(e){log("Graph2.getGraphExplorerAuthToken.onload: "+e);}},
  1060. onerror: function(response) {try{
  1061. Graph2.currentUser.authToken="";
  1062. log("Graph2.getGraphExplorerAuthToken: error:"+response.responseText+"\n.",{level:3});
  1063. }catch(e){log("Graph2.getGraphExplorerAuthToken.onerror: "+e);}},
  1064. onabort: function(response) {try{
  1065. Graph2.currentUser.authToken="";
  1066. log("Graph2.getGraphExplorerAuthToken: Request aborted",{level:3});
  1067. }catch(e){log("Graph2.getGraphExplorerAuthToken.onabort: "+e);}},
  1068. ontimeout: function(response) {try{
  1069. Graph2.currentUser.authToken="";
  1070. log("Graph.getGraphExplorerAuthToken: Request timeout",{level:3});
  1071. }catch(e){log("Graph2.getGraphExplorerAuthToken.ontimeout: "+e);}}
  1072. });
  1073. }catch(e){log("Graph2.getGraphExplorerAuthToken: "+e);}},
  1074. getAuthToken: function (callback){try{
  1075. getGraphExplorerAuthToken(callback);
  1076. }catch(e){log("Graph.getAuthToken: "+e);}},
  1077.  
  1078. likePost: function(params){try{
  1079. /*
  1080. postID
  1081. callback
  1082. post
  1083. responseText <--passback
  1084. */
  1085. var req; req=GM_xmlhttpRequest({
  1086. method: "POST",
  1087. url: "https://graph.facebook.com/v1.0/"+params.postID+"/likes?access_token="+Graph2.currentUser.authToken,
  1088. timeout: Graph2.fetchTimeout*1000,
  1089. onload: function(response) {try{
  1090. params.responseText = response.responseText
  1091. if (response.responseText=="true") {
  1092. if (params.callback) params.callback(params.post);
  1093. } else {
  1094. //log(response.responseText);
  1095. //hande in whatever called this function
  1096. }
  1097. }catch(e){log("Graph2.likePost.onload: "+e);}},
  1098. onerror: function(response) {try{
  1099. params.responseText = response.responseText
  1100. }catch(e){log("Graph2.likePost.onerror: "+e);}},
  1101. onabort: function(response) {try{
  1102. params.responseText = response.responseText
  1103. }catch(e){log("Graph2.likePost.onabort: "+e);}},
  1104. ontimeout: function(response) {try{
  1105. params.responseText = response.responseText
  1106. }catch(e){log("Graph2.likePost.ontimeout: "+e);}}
  1107. });
  1108. }catch(e){log("Graph2.likePost: "+e);}},
  1109.  
  1110. unlikePost: function(params){try{
  1111. /*
  1112. postID
  1113. callback
  1114. post
  1115. responseText <--passback
  1116. */
  1117. var req; req=GM_xmlhttpRequest({
  1118. method: "DELETE",
  1119. url: "https://graph.facebook.com/v1.0/"+params.postID+"/likes?access_token="+Graph2.currentUser.authToken,
  1120. timeout: Graph2.fetchTimeout*1000,
  1121. onload: function(response) {try{
  1122. params.responseText = response.responseText
  1123. if (params.callback) params.callback(params.post);
  1124. }catch(e){log("Graph2.unlikePost.onload: "+e);}},
  1125. onerror: function(response) {try{
  1126. params.responseText = response.responseText
  1127. }catch(e){log("Graph2.unlikePost.onerror: "+e);}},
  1128. onabort: function(response) {try{
  1129. params.responseText = response.responseText
  1130. }catch(e){log("Graph2.unlikePost.onabort: "+e);}},
  1131. ontimeout: function(response) {try{
  1132. params.responseText = response.responseText
  1133. }catch(e){log("Graph2.unlikePost.ontimeout: "+e);}}
  1134. });
  1135. }catch(e){log("Graph2.unlikePost: "+e);}},
  1136.  
  1137. commentPost: function(params){try{
  1138. /*
  1139. postID
  1140. callback
  1141. post
  1142. comment
  1143. responseText <--passback
  1144. */
  1145. var req; req=GM_xmlhttpRequest({
  1146. method: "POST",
  1147. url: "https://graph.facebook.com/v1.0/"+params.postID+"/comments?access_token="+Graph2.currentUser.authToken+"&message="+params.comment,
  1148. timeout: Graph2.fetchTimeout*1000,
  1149. onload: function(response) {try{
  1150. params.responseText = response.responseText
  1151. if (response.responseText=="true") {
  1152. if (params.callback) params.callback(params.post);
  1153. } else {
  1154. //log(response.responseText);
  1155. }
  1156. }catch(e){log("Graph2.commentPost.onload: "+e);}},
  1157. onerror: function(response) {try{
  1158. params.responseText = response.responseText
  1159. }catch(e){log("Graph2.commentPost.onerror: "+e);}},
  1160. onabort: function(response) {try{
  1161. params.responseText = response.responseText
  1162. }catch(e){log("Graph2.commentPost.onabort: "+e);}},
  1163. ontimeout: function(response) {try{
  1164. params.responseText = response.responseText
  1165. }catch(e){log("Graph2.commentPost.ontimeout: "+e);}}
  1166. });
  1167. }catch(e){log("Graph2.commentPost: "+e);}},
  1168. getCurrentUser : function(params){try{
  1169. /*
  1170. retires_noToken <-- counter for retries without successfully finding the token
  1171. responseText <--passback
  1172. */
  1173. Graph2.getUser({
  1174. userID:"me",
  1175. callback:function(){Graph2.procCurrentUser(params);}
  1176. });
  1177. }catch(e){log("Graph2.getCurrentUser: "+e);}},
  1178. procCurrentUser : function(params){try{
  1179. /*
  1180. responseText
  1181. */
  1182. var data = JSON.parse(params.responseText);
  1183. if (data["id"]||null){
  1184. //expected data exists
  1185. Graph2.currentUser.id=data["id"||null];
  1186. //Graph2.currentUser.alias=(data["username"]||null);
  1187. Graph2.currentUser.name=(data["name"]||null);
  1188. Graph2.currentUser.timezone=(data["timezone"]||null);
  1189. Graph2.currentUser.locale=(data["locale"]||null);
  1190.  
  1191. if (params.callback) setTimeout(function(){params.callback(Graph2.currentUser);},0);
  1192. } else if (data["error"]||null) {
  1193. var emsg=data.error.message||null;
  1194. //check for session expired
  1195. if (emsg.find("Session has expired")||emsg.find("session is invalid")){
  1196. //session expired or logged out, get a new token
  1197. Graph2.currentUser.authToken="";
  1198. params["retries_expToken"]=(params["retries_expToken"])?params["retries_expToken"]+1:1; //count retries
  1199. if (params["retries_expToken"]<3) {
  1200. setTimeout(function(){Graph2.getAuthToken({callback:Graph2.getCurrentUser});},0);
  1201. } else log("Graph2.procCurrentUser: cannot refresh expired fb auth token",{level:3});
  1202. } else if (emsg) log("Graph2.procCurrentUser: "+emsg,{level:3});
  1203.  
  1204. } else log("Graph2.procCurrentUser: response was unrecognized",{level:3});
  1205. }catch(e){log("Graph2.procCurrentUser: "+e);}},
  1206. getUser : function(params){try{
  1207. /*
  1208. userID <-- "me" for current user
  1209. callback
  1210. retires_noToken <-- counter for retries without successfully finding the token
  1211. responseText <--passback
  1212. */
  1213. //log("Graph.getUser()");
  1214. params=params || {};
  1215. if (!Graph2.currentUser.authToken) {
  1216. params["retries_noToken"]=(params["retries_noToken"])?params["retries_noToken"]+1:1; //count retries
  1217. if (params["retries_noToken"]<3) {
  1218. Graph2.getAuthToken(function(){Graph2.getUser(params);} );
  1219. } else {
  1220. log("Graph2.getUser: cannot get new fb auth token",{level:3});
  1221. return;
  1222. }
  1223. return;
  1224. }
  1225. var URL="https://graph.facebook.com/v1.0/"+params.userID+"?access_token="+Graph2.currentUser.authToken;
  1226. var req; req=GM_xmlhttpRequest({
  1227. method: "GET",
  1228. url: URL,
  1229. timeout: Graph2.fetchTimeout*1000,
  1230. onload: function(response) {try{
  1231. if (response){
  1232. params.responseText = response.responseText;
  1233. } else log("Graph2.getUser: response was empty",{level:3});
  1234. }catch(e){log("Graph2.getUser.onload: "+e);}},
  1235.  
  1236. onabort: function(response) {try{
  1237. params.responseText = response.responseText;
  1238. log("Graph2.getUser: Request aborted");
  1239. }catch(e){log("Graph2.getUser.onabort: "+e);}},
  1240. ontimeout: function(response) {try{
  1241. params.responseText = response.responseText;
  1242. log("Graph2.getUser: Request timeout");
  1243. }catch(e){log("Graph2.getUser.ontimeout: "+e);}},
  1244.  
  1245. onerror: function(response) {try{
  1246. params.responseText = response.responseText;
  1247. if (response.responseText=="") {
  1248. log("Graph2.getUser: responseText was empty. Check to make sure your browser is online.", {level:5});
  1249. } else {
  1250. log("Graph2.getUser: Request error");
  1251. }
  1252. }catch(e){log("Graph2.getUser.onerror: "+e);}}
  1253. });
  1254. }catch(e){log("Graph2.getUser: "+e);}},
  1255. getPost : function() {
  1256. },
  1257. getPosts : function() {
  1258. },
  1259. getIsFriend : function(userId) {
  1260. return ((Graph2.friends[userId]||null)!=null);
  1261. },
  1262. getFriends : function(params) {try{
  1263. params=params || {};
  1264. if (!Graph2.currentUser.authToken) {
  1265. params["retries_noToken"]=(params["retries_noToken"])?params["retries_noToken"]+1:1; //count retries
  1266. if (params["retries_noToken"]<3) {
  1267. Graph2.getAuthToken(function(){Graph2.getFriends(params);} );
  1268. } else {
  1269. log("Graph2.getFriends: cannot get new fb auth token",{level:3});
  1270. return;
  1271. }
  1272. return;
  1273. }
  1274. var URL="https://graph.facebook.com/v1.0/me/friends?limit=5000&access_token="+Graph2.currentUser.authToken;
  1275. var req; req=GM_xmlhttpRequest({
  1276. method: "GET",
  1277. url: URL,
  1278. timeout: Graph2.fetchTimeout*1000,
  1279. onload: function(response) {try{
  1280. if (response){
  1281. params.responseText = response.responseText;
  1282. setTimeout(function(){Graph2.procFriends(params);},0);
  1283. } else log("Graph2.getFriends: response was empty",{level:3});
  1284. }catch(e){log("Graph2.getFriends.onload: "+e);}},
  1285.  
  1286. onabort: function(response) {try{
  1287. params.responseText = response.responseText;
  1288. log("Graph2.getFriends: Request aborted");
  1289. }catch(e){log("Graph2.getFriends.onabort: "+e);}},
  1290. ontimeout: function(response) {try{
  1291. params.responseText = response.responseText;
  1292. log("Graph2.getFriends: Request timeout");
  1293. }catch(e){log("Graph2.getFriends.ontimeout: "+e);}},
  1294.  
  1295. onerror: function(response) {try{
  1296. params.responseText = response.responseText;
  1297. log("Graph2.getFriends: Request error");
  1298. }catch(e){log("Graph2.getFriends.onerror: "+e);}}
  1299. });
  1300. }catch(e){log("Graph2.getFriends: "+e);}},
  1301.  
  1302. procFriends : function(params){try{
  1303. /*
  1304. responseText
  1305. */
  1306. var data = JSON.parse(params.responseText);
  1307. if (data["data"]||null){
  1308.  
  1309. //index friend user data
  1310. for (var user in data.data) {
  1311. Graph2.friends[user.id] = user;
  1312. }
  1313. if (params.callback) setTimeout(function(){params.callback(Graph2.friends);},0);
  1314. } else log("Graph2.procFriends: response was unrecognized",{level:3});
  1315. }catch(e){log("Graph2.procFriends: "+e);}},
  1316. getIsUserInFriendList : function() {
  1317. },
  1318. getFriendLists : function(params) {try{
  1319. params=params || {};
  1320. if (!Graph2.currentUser.authToken) {
  1321. params["retries_noToken"]=(params["retries_noToken"])?params["retries_noToken"]+1:1; //count retries
  1322. if (params["retries_noToken"]<3) {
  1323. Graph2.getAuthToken(function(){Graph2.getFriendLists(params);} );
  1324. } else {
  1325. log("Graph2.getFriendLists: cannot get new fb auth token",{level:3});
  1326. return;
  1327. }
  1328. return;
  1329. }
  1330. var URL="https://graph.facebook.com/v1.0/me/friendlists?limit=5000&access_token="+Graph2.currentUser.authToken;
  1331. var req; req=GM_xmlhttpRequest({
  1332. method: "GET",
  1333. url: URL,
  1334. timeout: Graph2.fetchTimeout*1000,
  1335. onload: function(response) {try{
  1336. if (response){
  1337. params.responseText = response.responseText;
  1338. setTimeout(function(){Graph2.procFriend=Lists(params);},0);
  1339. } else log("Graph2.getFriendLists: response was empty",{level:3});
  1340. }catch(e){log("Graph2.getFriendLists.onload: "+e);}},
  1341.  
  1342. onabort: function(response) {try{
  1343. params.responseText = response.responseText;
  1344. log("Graph2.getFriendLists: Request aborted");
  1345. }catch(e){log("Graph2.getFriendLists.onabort: "+e);}},
  1346. ontimeout: function(response) {try{
  1347. params.responseText = response.responseText;
  1348. log("Graph2.getFriendLists: Request timeout");
  1349. }catch(e){log("Graph2.getFriendLists.ontimeout: "+e);}},
  1350.  
  1351. onerror: function(response) {try{
  1352. params.responseText = response.responseText;
  1353. log("Graph2.getFriendLists: Request error");
  1354. }catch(e){log("Graph2.getFriendLists.onerror: "+e);}}
  1355. });
  1356. }catch(e){log("Graph2.getFriendLists: "+e);}},
  1357. procFriendLists : function(params){try{
  1358. /*
  1359. responseText
  1360. */
  1361. var data = JSON.parse(params.responseText);
  1362. if (data["data"]||null){
  1363.  
  1364. //index friend user data
  1365. for (var list in data.data) {
  1366. Graph2.friendLists[list.id] = list;
  1367. }
  1368. if (params.callback) setTimeout(function(){params.callback(Graph2.friendLists);},0);
  1369. } else log("Graph2.procFriendLists: response was unrecognized",{level:3});
  1370. }catch(e){log("Graph2.procFriendLists: "+e);}}
  1371. }
  1372. log("Graph initialized");
  1373. })();