Greasy Fork is available in English.

WM Graph API Interface (Beta Branch)

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

Version vom 04.09.2014. Aktuellste Version

Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greatest.deepsurf.us/scripts/420/16186/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.2
  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/POST_ID/likes?access_token=
  28. var req; req=GM_xmlhttpRequest({
  29. method: "POST",
  30. url: "https://graph.facebook.com/"+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/"+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/"+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/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/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(","));
  365. } else {
  366. URL=URL.replace("{3}","SELECT uid2 FROM friend WHERE uid1=me() LIMIT 5000");
  367. }*/
  368.  
  369. //as of FQL 2.1, WM can no longer request data by specific friend UID
  370. //so by default we now ALWAYS just use a list of all of our friends
  371. URL=URL.replace("{3}","SELECT uid2 FROM friend WHERE uid1=me() LIMIT 5000");
  372. //get older posts
  373. //verify that the feed "until" time does not violate olderLimit set by user
  374. if (params.direction<0){
  375. URL=URL.replace("{2}"," AND created_time < "+params.currentEdge);
  376. //get newer posts
  377. } else if (params.direction>0){
  378. URL=URL.replace("{2}"," AND created_time > "+params.currentEdge);
  379. //fetch at current time
  380. } else {
  381. URL=URL.replace("{2}","");
  382. }
  383.  
  384. //filters by apps requested
  385. //unless no apps were passed or we specified no app filtering
  386. if ((params.apps||null) && !(params.noAppFiltering||null)){
  387. URL=URL.replace("{1}"," AND app_id IN ("+params.apps.join(",")+")");
  388. } else {
  389. //no app filtering, let WM do this internally
  390. URL=URL.replace("{1}","");
  391. }
  392. //add the user defined fetchQty
  393. URL=URL.replace("{4}","+LIMIT+"+(params.limit||25));
  394. //encode the url
  395. URL=URL_prefix+encodeURI(URL).replace(/\:/,"%3A").replace(/\#/,"%23");
  396.  
  397. log("Graph.fetchPostsFQL: processing feed <a target='_blank' href='"+URL+"'>"+URL+"</a>");
  398. //remember this request
  399. Graph.requests.push(mergeJSON(params));
  400.  
  401. //make the request
  402. var req; req=GM_xmlhttpRequest({
  403. method: "GET",
  404. url: URL,
  405. timeout: Graph.fetchTimeout*1000,
  406. onload: function(response) {try{
  407. //show dev tools
  408. if (opts && debug && !isChrome) if (opts.devDebugGraphData) {
  409. var pkg=debug.print("Graph.fetchPostsFQL.onload.devDebugGraphData: ");
  410. pkg.msg.appendChild(createElement("button",{type:"button",onclick:function(){
  411. promptText(response.responseText);
  412. }},[
  413. createElement("img",{src:"http://i1181.photobucket.com/albums/x430/merricksdad/array.png",title:"Show Data",style:"width:16px;height:16px; vertical-align:bottom;"})
  414. ]));
  415. }
  416. //remove the memory that a request is out
  417. var r = Graph.matchRequest(params);
  418. if (r!=-1) Graph.requests.remove(r);
  419.  
  420. if (response){
  421. try{
  422. //convert to JSON
  423. var data = JSON.parse(response.responseText);
  424. //manage the return object
  425. if (exists(data.data)) {
  426. //there should be two return queries under data
  427. //zip the two together by matching the name to the source_id in the post
  428. var realData = data.data[0].fql_result_set;
  429. var nameData = data.data[1].fql_result_set;
  430. var uidKeys = {};
  431. for (var n=0,l=nameData.length;n<l;n++){
  432. uidKeys[nameData[n].uid.toString()]=nameData[n].name;
  433. }
  434.  
  435. for (var p=0,l=realData.length;p<l;p++){
  436. realData[p].fromName = (uidKeys[realData[p].source_id.toString()]||"undefined");
  437. }
  438. data.data=realData;
  439. //store posts
  440. if (data.data.length) log("Graph.fetchPostsFQL.onLoad: "+data.data.length+" posts received. Validating data...");
  441. else log("Graph.fetchPostsFQL.onLoad: facebook returned an empty data set.");
  442. //no paging exists in the FQL system, we make our own
  443. var gotMoreToDo=false;
  444. var lastPullOldestPost=null;
  445. var lastPullNewestPost=null;
  446. if (data.data.length) {
  447. lastPullOldestPost=data.data.last().created_time;
  448. lastPullNewestPost=data.data[0].created_time;
  449. }
  450. if ((params.targetEdge||null) && (data.data.length)) {
  451. gotMoreToDo = (params.direction<0)?
  452. (lastPullOldestPost > params.targetEdge): //keep fetching older
  453. (lastPullNewestPost < params.targetEdge); //keep fetching newer
  454. }
  455. //read them in backward
  456. if (data.data.length) for (var i=data.data.length-1;i>=0;i--) {
  457. var post=data.data[i];
  458.  
  459. //exclude posts already in our repository
  460. if (Graph.posts[post["post_id"]]!=1) {
  461.  
  462. //store a reference to this post
  463. Graph.posts[post["post_id"]]=1;
  464.  
  465. //send the post back to the callback function here
  466. params.callback(post);
  467. }
  468. }
  469. //process the edge handler for any request that returned posts
  470. var edgeMsg = {friends:params.friends,apps:params.apps,edge:{}};
  471. if (params.direction>=0) edgeMsg.edge.newer=lastPullNewestPost;
  472. if (params.direction<=0) edgeMsg.edge.older=lastPullOldestPost;
  473. if (data.data.length) if (params.edgeHandler||null) params.edgeHandler(edgeMsg);
  474. //go back and do another request if we have specified we have more to do
  475. //this is for use with fetchHours and similar functions
  476. if (gotMoreToDo) {
  477. log("Graph.fetchPostsFQL.onload: was not able to get enough in one return, going back for more...");
  478. var newParams = mergeJSON(params);
  479. newParams.currentEdge=(params.direction<0)?lastPullOldestPost:lastPullNewestPost;
  480. Graph.fetchPosts(newParams);
  481. }
  482.  
  483.  
  484. } else if (data.error||null) {
  485. //check for session expired
  486. if ((data.error.message||"").find("Session has expired")){
  487. //session expired, get a new token
  488. Graph.authToken="";
  489. params["retries_expToken"]=(params["retries_expToken"])?params["retries_expToken"]+1:1; //count retries
  490. if (params["retries_expToken"]<3) {
  491. Graph.requestAuthCodeB(function(){Graph.fetchPosts(params);} );
  492. } else log("Graph.fetchPostsFQL: cannot refresh expired fb auth token",{level:3});
  493. }
  494. else if (data.error.message||null) log("Graph.fetchPosts: "+data.error.message,{level:3});
  495.  
  496. } else log("Graph.fetchPostsFQL: response was unrecognized",{level:3});
  497. data=null;
  498. } catch (e){log("Graph.fetchPostsFQL: response error: "+e+": "+response);}
  499. } else log("Graph.fetchPostsFQL: response was empty",{level:3});
  500. if(req)req=null;
  501. }catch(e){log("Graph.fetchPostsFQL.onload: "+e);}},
  502.  
  503. onabort: function(response) {try{
  504. //remove the memory that a request is out
  505. var r = Graph.matchRequest(params);
  506. if (r!=-1) Graph.requests.remove(r);
  507. log("Graph.fetchPostsFQL: aborted: "+response.responseText);
  508. if(req)req=null;
  509. }catch(e){log("Graph.fetchPostsFQL.onabort: "+e);}},
  510.  
  511. ontimeout: function(response) {try{
  512. //remove the memory that a request is out
  513. params.timeouts++;
  514. var r = Graph.matchRequest(params);
  515. if (r!=-1) Graph.requests.remove(r);
  516. log("Graph.fetchPostsFQL: timeout: retry="+(params.timeouts<3)+", "+response.responseText);
  517. if(req)req=null;
  518. if (params.timeouts<3) Graph.fetchPosts(params);
  519. }catch(e){log("Graph.fetchPostsFQL.ontimeout: "+e);}},
  520.  
  521. onerror: function(response) {try{
  522. //remove the memory that a request is out
  523. var r = Graph.matchRequest(params);
  524. if (r!=-1) Graph.requests.remove(r);
  525. log("Graph.fetchPostsFQL: error: "+response.responseText);
  526. if(req)req=null;
  527. }catch(e){log("Graph.fetchPostsFQL.onerror: "+e);}}
  528. });
  529. }catch(e){log("Graph.fetchPostsFQL_B: "+e);}},
  530. fetchPostsFQL: function(params){try{
  531. log("Graph.fetchPostsFQL("+((params.newer)?"newer":(params.older)?"older":"")+")",{level:1});
  532. params=params || {};
  533. params.timeouts=params.timeouts||0;
  534. var bypassMatchRequest = (params.range||null)?true:false;
  535. //remember the target position if this is a ranged search
  536. //we'll pass targetrange back to this function later if we need to fetch more
  537. if (params.range||null){
  538. if (params.range.oldedge||null) params.targetedge = params.range.oldedge;
  539. }
  540.  
  541. //validate auth token
  542. if (!Graph.authToken) {
  543. log("Graph.fetchPostsFQL: no authToken, get one");
  544. params["retries_noToken"]=(params["retries_noToken"])?params["retries_noToken"]+1:1; //count retries
  545. if (params["retries_noToken"]<3) {
  546. Graph.requestAuthCodeB(function(){Graph.fetchPostsFQL(params);} );
  547. } else {
  548. log("Graph.fetchPostsFQL: cannot get new fb auth token",{level:3});
  549. return {getAuthTokenFailed:true};
  550. }
  551. return;
  552. }
  553.  
  554. //check if there is a request already out with this fb id and matches the direction
  555. var r=Graph.matchRequest(params);
  556. if (!bypassMatchRequest) if (r!=-1){
  557. if (Graph.requests[r].older==null && Graph.requests[r].newer==null) {
  558. log("Graph.fetchPostsFQL: the initial request for data has not been returned yet",{level:3});
  559. return {initRequestSlow:true};
  560. } else {
  561. log("Graph.fetchPostsFQL: a request is already out for posts in that direction and has not returned",{level:3});
  562. return {requestAlreadyOut:true};
  563. }
  564. }
  565.  
  566. var feed=params.feed||null;
  567. var filter = (params.filter||"default");
  568. //create default filter instances when they do not exist
  569. if (params.groupApps||null) {
  570. //set our filter to our first app in the groupApps
  571. //this will be used below various times
  572. filter = "app_"+params.groupApps[0];
  573. if (feed||null) for (var a=0,l=params.groupApps.length;a<l;a++) {
  574. var filtName = "app_"+params.groupApps[a];
  575. if (!(feed.filters[filtName]||null)) feed.addFilter({id:filtName}); //create filter instance if needed
  576. }
  577. } else {
  578. if (feed||null) if (!(feed.filters[filter]||null)) feed.addFilter({id:filter}); //create filter instance if needed
  579. }
  580. //compile feed request strings
  581. var URL_prefix="https://graph.facebook.com/fql?access_token={0}&q=";
  582. 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)\"}";
  583. URL_prefix=URL_prefix.replace("{0}",Graph.authToken);
  584. //specialize call for specific friend post requests
  585. if (params.specificFriend||null) {
  586. URL=URL.replace("{3}",feed.id);
  587. } else {
  588. URL=URL.replace("{3}","SELECT uid2 FROM friend WHERE uid1=me() LIMIT 5000");
  589. }
  590. //get older posts
  591. //verify that the feed "until" time does not violate olderLimit set by user
  592. if (params.older){
  593. var edge=(params.range||null)?params.range.oldedge:feed.filters[filter].oldedge;
  594. if (edge||null){
  595. var limit=(params.limit||null); //this is not FB search limit keyword, this is a WM timelimit
  596. var timeNow=timeStamp();
  597. //no oldest post limit on range fetches
  598. if (params.range||null) limit=null;
  599. if (limit) {
  600. if ((timeNow-(edge*1000)) > limit) {
  601. log("Graph.fetchPosts("+params.feed.url+"): the user-set older limit of this feed has been reached",{level:2});
  602. return {olderLimitReached:true};
  603. }
  604. }
  605. URL=URL.replace("{2}"," AND created_time < "+edge);
  606.  
  607. } else {
  608. log("Graph.fetchPostsFQL("+params.feed.url+"): The previous result did not return pagination. Restarting fetching from current time.");
  609. URL=URL.replace("{2}","");
  610. }
  611. //get newer posts
  612. } else if (params.newer){
  613. var edge=(params.range||null)?params.range.newedge:feed.filters[filter].newedge;
  614. if (exists(edge)) {
  615. URL=URL.replace("{2}"," AND created_time > "+edge);
  616. }
  617. //fetch at current time
  618. } else {
  619. URL=URL.replace("{2}","");
  620. }
  621.  
  622. //filters come in the form of "app_123456789012"
  623. if (params.groupApps||null) {
  624. //fetch posts for multiple apps at once
  625. URL=URL.replace("{1}"," AND app_id IN ("+params.groupApps.join(",")+")");
  626. } else if (filter!=undefined && filter!=null){
  627. URL=URL.replace("{1}"," AND app_id IN ("+filter.split("app_")[1]+")");
  628. } else {
  629. //no filter, nothing passed
  630. //this should never happen
  631. URL=URL.replace("{1}","");
  632. }
  633. //add the user defined fetchQty
  634. URL=URL.replace("{4}","+LIMIT+"+(params.fetchQty||25));
  635. //encode the url
  636. URL=URL_prefix+encodeURI(URL).replace(/\:/,"%3A").replace(/\#/,"%23");
  637.  
  638. log("Graph.fetchPostsFQL: processing feed <a target='_blank' href='"+URL+"'>"+URL+"</a>");
  639. //console.log(URL);
  640. //return;
  641. //remember this request
  642. Graph.requests.push({feed:params.feed, older:params.older, newer:params.newer, filter:filter, groupApps:params.groupApps, specificFriend:params.specificFriend});
  643. //console.log("request pushed");
  644.  
  645. //return;
  646. var req; req=GM_xmlhttpRequest({
  647. method: "GET",
  648. url: URL,
  649. timeout: Graph.fetchTimeout*1000,
  650. onload: function(response) {try{
  651. //show dev tools
  652. if (opts && debug && !isChrome) if (opts.devDebugGraphData) {
  653. var pkg=debug.print("Graph.fetchPostsFQL.onload.devDebugGraphData: ");
  654. pkg.msg.appendChild(createElement("button",{type:"button",onclick:function(){
  655. //response.responseText.toClipboard();
  656. promptText(response.responseText);
  657. }},[
  658. createElement("img",{src:"http://i1181.photobucket.com/albums/x430/merricksdad/array.png",title:"Show Data",style:"width:16px;height:16px; vertical-align:bottom;"})
  659. ]));
  660. }
  661. //remove the memory that a request is out
  662. var r = Graph.matchRequest(params);
  663. if (r!=-1) Graph.requests.remove(r);
  664.  
  665. if (response){
  666. try{
  667. //convert to JSON
  668. var data = JSON.parse(response.responseText);
  669. //manage the return object
  670. if (exists(data.data)) {
  671. //log("response contains data");
  672. //there should be two return queries under data
  673. //zip the two together by matching the name to the source_id in the post
  674. var realData = data.data[0].fql_result_set;
  675. var nameData = data.data[1].fql_result_set;
  676. var uidKeys = {};
  677. for (var n=0,l=nameData.length;n<l;n++){
  678. uidKeys[nameData[n].uid.toString()]=nameData[n].name;
  679. }
  680.  
  681. for (var p=0,l=realData.length;p<l;p++){
  682. realData[p].fromName = (uidKeys[realData[p].source_id.toString()]||"undefined");
  683. }
  684. data.data=realData;
  685. //store posts
  686. if (data.data.length) log("Graph.fetchPostsFQL.onLoad: "+data.data.length+" posts received. Validating data...");
  687. else log("Graph.fetchPostsFQL.onLoad: facebook returned an empty data set.");
  688. //no paging exists in the FQL system, we make our own
  689. var gotMoreToDo=false;
  690. var lastPullOldestPost=null;
  691. var lastPullNewestPost=null;
  692. if (data.data.length) {
  693. lastPullOldestPost=data.data.last().created_time;
  694. lastPullNewestPost=data.data[0].created_time;
  695. }
  696. if ((params.targetedge||null) && (data.data.length)) {
  697. gotMoreToDo = (lastPullOldestPost > params.targetedge);
  698. }
  699. //read them in backward
  700. if (data.data.length) for (var i=data.data.length-1;i>=0;i--) {
  701. var post=data.data[i];
  702.  
  703. Graph.validatePost({
  704. post:post,
  705. callback:params.callback||null,
  706. older:params.older,
  707. newer:params.newer
  708. });
  709.  
  710. }
  711. //go back and do another request if we have specified we have more to do
  712. //this is for use with fetchHours and similar functions
  713. if (gotMoreToDo) {
  714. log("Graph.fetchPostsFQL.onload: was not able to get enough in one return, going back for more...");
  715. //clone the last set of params
  716. var newParams = mergeJSON(params);
  717. newParams.range={oldedge:0,newedge:0}; //new instance to prevent byRef errors
  718. //update the range settings
  719. newParams.range.newedge=lastPullOldestPost;
  720. newParams.range.oldedge=params.targetedge; //remember the original passed oldest data to target
  721. //make the next request
  722. Graph.fetchPosts(newParams);
  723. }
  724. //start cleanup
  725. if (params.callback) delete params.callback;
  726.  
  727.  
  728. //capture the next and prev urls, but dont overwrite current known time boundaries
  729. if (data.data.length){
  730. if (params.groupApps||null){
  731. //manage all filters at once from the group-fetch apps array
  732. for (var n=0,l=params.groupApps.length;n<l;n++){
  733. var filtName = "app_"+params.groupApps[n];
  734. if (!params.newer && !params.older) {
  735. feed.filters[filtName].newedge = lastPullNewestPost;
  736. feed.filters[filtName].oldedge = lastPullOldestPost;
  737. }
  738. if (params.newer) feed.filters[filtName].newedge = lastPullNewestPost;
  739. if (params.older) feed.filters[filtName].oldedge = lastPullOldestPost;
  740. }
  741. } else if (filter!=undefined && filter!=null) {
  742. //if the current request was a recent posts pull, set both edges
  743. if (!params.newer && !params.older) {
  744. feed.filters[filter].newedge = lastPullNewestPost;
  745. feed.filters[filter].oldedge = lastPullOldestPost;
  746. }
  747.  
  748. //if the current request got newer posts, push the newer post edge
  749. if (params.newer) feed.filters[filter].newedge = lastPullNewestPost;
  750. //if the current request got older posts, push the older post edge
  751. if (params.older) feed.filters[filter].oldedge = lastPullOldestPost;
  752. }
  753. }
  754.  
  755. } else if (data.error||null) {
  756. //check for session expired
  757. if ((data.error.message||"").find("Session has expired")){
  758. //session expired, get a new token
  759. Graph.authToken="";
  760. params["retries_expToken"]=(params["retries_expToken"])?params["retries_expToken"]+1:1; //count retries
  761. if (params["retries_expToken"]<3) {
  762. Graph.requestAuthCodeB(function(){Graph.fetchPosts(params);} );
  763. } else log("Graph.fetchPostsFQL: cannot refresh expired fb auth token",{level:3});
  764. }
  765. else if (data.error.message||null) log("Graph.fetchPosts: "+data.error.message,{level:3});
  766.  
  767. } else log("Graph.fetchPostsFQL: response was unrecognized",{level:3});
  768. data=null;
  769. } catch (e){log("Graph.fetchPostsFQL: response error: "+e+": "+response);}
  770. } else log("Graph.fetchPostsFQL: response was empty",{level:3});
  771. if(req)req=null;
  772. }catch(e){log("Graph.fetchPostsFQL.onload: "+e);}},
  773.  
  774. onabort: function(response) {try{
  775. //remove the memory that a request is out
  776. var r = Graph.matchRequest(params);
  777. if (r!=-1) Graph.requests.remove(r);
  778. log("Graph.fetchPostsFQL: aborted: "+response.responseText);
  779. if(req)req=null;
  780. }catch(e){log("Graph.fetchPostsFQL.onabort: "+e);}},
  781.  
  782. ontimeout: function(response) {try{
  783. //remove the memory that a request is out
  784. params.timeouts++;
  785. var r = Graph.matchRequest(params);
  786. if (r!=-1) Graph.requests.remove(r);
  787. log("Graph.fetchPostsFQL: timeout: retry="+(params.timeouts<3)+", "+response.responseText);
  788. if(req)req=null;
  789. if (params.timeouts<3) Graph.fetchPosts(params);
  790. }catch(e){log("Graph.fetchPostsFQL.ontimeout: "+e);}},
  791.  
  792. onerror: function(response) {try{
  793. //remove the memory that a request is out
  794. var r = Graph.matchRequest(params);
  795. if (r!=-1) Graph.requests.remove(r);
  796. log("Graph.fetchPostsFQL: error: "+response.responseText);
  797. if(req)req=null;
  798. }catch(e){log("Graph.fetchPostsFQL.onerror: "+e);}}
  799. });
  800. }catch(e){log("Graph.fetchPostsFQL: "+e);}},
  801. /* fetchPosts details:
  802. params = {
  803. feed:<feed reference>,
  804. filter:<appID>,
  805. next:<url containing 'until'>,
  806. prev:<url containing 'since'>,
  807. callback:<where to ship the return data>,
  808. retries_noToken:<counter>,
  809. fetchQty:<number>,
  810. specific:<specific range object>
  811. }
  812. */
  813. fetchPosts: function(params){try{
  814. log("Graph.fetchPosts is deprecated. Use Graph.fetchPostsFQL.");
  815. return Graph.fetchPostsFQL(params);
  816. log("Graph.fetchPosts()",{level:1});
  817. params=params || {};
  818. params.timeouts=params.timeouts||0;
  819. var bypassMatchRequest = (params.range||null)?true:false;
  820. //remember the target position if this is a ranged search
  821. //the very first call we make is a "since" call, but all sequential calls are "until" calls due to FB's stupid pagination methods
  822. if (params.range||null){
  823. //log(params.range.since);
  824. if (params.range.since||null) params.targetUntil = params.range.since;
  825. }
  826. if (!Graph.authToken) {
  827. log("Graph.fetchPosts: no authToken, get one");
  828. params["retries_noToken"]=(params["retries_noToken"])?params["retries_noToken"]+1:1; //count retries
  829. if (params["retries_noToken"]<3) {
  830. Graph.requestAuthCodeB(function(){Graph.fetchPosts(params);} );
  831. } else {
  832. log("Graph.fetchPosts: cannot get new fb auth token",{level:3});
  833. return {getAuthTokenFailed:true};
  834. }
  835. return;
  836. }
  837.  
  838. //check if there is a request already out with this fb id and matches the direction
  839. var r=Graph.matchRequest(params);
  840. if (!bypassMatchRequest) if (r!=-1){
  841. if (Graph.requests[r].next==null && Graph.requests[r].prev==null) {
  842. log("Graph.fetchPosts: the initial request for data has not been returned yet",{level:3});
  843. return {initRequestSlow:true};
  844. } else {
  845. log("Graph.fetchPosts: a request is already out for posts in that direction and has not returned",{level:3});
  846. return {requestAlreadyOut:true};
  847. }
  848. }
  849.  
  850. //for each user specified feed source, get posts
  851. var feed=params.feed||null;
  852. var filter = (params.filter||"default");
  853. if (!(feed.filters[filter]||null)) feed.addFilter({id:filter}); //create filter instance if needed
  854.  
  855. var URL=feed.url+"?date_format=U&limit="+((params.range||null)?250:params.fetchQty)+"&access_token="+Graph.authToken;
  856. //get older posts
  857. //verify that the feed "until" time does not violate olderLimit set by user
  858. if (params.next || ((params.range||null)?params.range.until||null:null) ){
  859. var until=(params.range||null)?params.range.until:feed.filters[filter].next.getUrlParam("until");
  860. //debug.print(["var until",until]);
  861. if (until||null){
  862. var limit=(params.limit||null); //this is not FB search limit keyword, this is a WM timelimit
  863. var timeNow=timeStamp();
  864. //no oldest post limit on range fetches
  865. if (params.range||null) limit=null;
  866. var fixTime = (until.length < 10)?(until+"000"):until;
  867.  
  868. //debug.print(["var until:",until, until.length, fixTime])
  869. if (limit) {
  870. if ((timeNow-(fixTime)) > limit) {
  871. //log("Graph.fetchPosts("+params.feed.url+"): the user-set older limit of this feed has been reached",{level:2});
  872. return {olderLimitReached:true};
  873. }
  874. }
  875. URL+="&until="+fixTime;
  876. } else {
  877. log("Graph.fetchPosts("+params.feed.url+"): The previous result did not return pagination. Restarting fetching from current time.");
  878. }
  879. }
  880. //get newer posts
  881. //rules manager action fetchHours will be asking for a range staring at time X, so use range.since
  882. else if (params.prev || ((params.range||null)?params.range.since||null:null) ) {
  883. var since=(params.range||null)?params.range.since:feed.filters[filter].prev.getUrlParam("since");
  884. if (exists(since)) {
  885. URL+="&since="+since;
  886. }
  887. }
  888.  
  889. //add a filter if there is one
  890. if (exists(params.filter)) URL+="&filter="+filter; //check using params.filter, do not use filter here or it may inject "default"
  891.  
  892. log("Graph.fetchPosts: processing feed <a target='_blank' href='"+URL+"'>"+URL+"</a>");
  893. //remember this request
  894. Graph.requests.push({feed:params.feed, next:params.next, prev:params.prev, filter:filter});
  895.  
  896. var req; req=GM_xmlhttpRequest({
  897. method: "GET",
  898. url: URL,
  899. timeout: Graph.fetchTimeout*1000,
  900. onload: function(response) {try{
  901. //show dev tools
  902. if (opts && debug && !isChrome) if (opts.devDebugGraphData) {
  903. var pkg=debug.print("Graph.fetchPosts.onload.devDebugGraphData: ");
  904. pkg.msg.appendChild(createElement("button",{type:"button",onclick:function(){
  905. //response.responseText.toClipboard();
  906. promptText(response.responseText);
  907. }},[
  908. createElement("img",{src:"http://i1181.photobucket.com/albums/x430/merricksdad/array.png",title:"Show Data",style:"width:16px;height:16px; vertical-align:bottom;"})
  909. ]));
  910. }
  911. //remove the memory that a request is out
  912. var r = Graph.matchRequest(params);
  913. if (r!=-1) Graph.requests.remove(r);
  914.  
  915. if (response){
  916. try{
  917. //convert to JSON
  918. var data = JSON.parse(response.responseText);
  919. //add new posts to graph.posts
  920. if (exists(data.data)) {
  921. //log("response contains data");
  922.  
  923. //alert(JSON.stringify(data.data));
  924. //store posts
  925. if (data.data.length) log("Graph.fetchPosts.onLoad: "+data.data.length+" posts received. Validating data...");
  926. else log("Graph.fetchPosts.onLoad: facebook returned an empty data set.");
  927. var gotMoreToDo=false;
  928. if ((params.targetUntil||null) && (data.data.length) && (data.paging.next)) {
  929. var lastPullOldestPost=data.paging.next.getUrlParam("until");
  930. //2013/9/7: known facebook limit maximum is 500, but we are fetching in 250's
  931. //have we maxed out AND is oldest returned post newer than what we asked for
  932. gotMoreToDo = (data.data.length>=250) && (lastPullOldestPost > params.targetUntil);
  933. }
  934. if (data.data.length) for (var i=data.data.length-1;i>=0;i--) {
  935. var post=data.data[i];
  936.  
  937. Graph.validatePost({
  938. post:post,
  939. callback:params.callback||null,
  940. next:params.next
  941. });
  942.  
  943. }
  944. if (gotMoreToDo) {
  945. log("Graph.fetchPosts.onload: was not able to get enough in one return, going back for more...");
  946. //clone the last set of params
  947. var newParams = mergeJSON(params);
  948. newParams.range={since:0,until:0}; //new instance to prevent byRef errors
  949. //update the range settings
  950. //newParams.range.since=data.paging.previous.getUrlParam("since");
  951. newParams.range.until=data.paging.next.getUrlParam("until");
  952. //log([params.range.since,newParams.range.since,newParams.range.until,timeStampNoMS()]);
  953. newParams.targetUntil = params.range.since; //remember the original passed oldest data to target
  954. //make the next request
  955. Graph.fetchPosts(newParams);
  956. }
  957. //start cleanup
  958. if (params.callback) delete params.callback;
  959.  
  960.  
  961. //capture the next and prev urls, but dont overwrite current known time boundaries
  962. if (data.paging||null){
  963. //if this is the first time we've used this object, remember its locations
  964. if (!feed.filters[filter].next) feed.filters[filter].next = data.paging.next;
  965. if (!feed.filters[filter].prev) feed.filters[filter].prev = data.paging.prev;
  966.  
  967. //if the current request did not get older posts, push the newer post bracket
  968. if (!params.prev) feed.filters[filter].next = data.paging.next;
  969. //if the current request did not get newer posts, push the older post bracket
  970. if (!params.next) feed.filters[filter].prev = data.paging.previous;
  971. } else {
  972. log("Graph.fetchPosts.onLoad: facebook failed to return pagination data.")
  973. }
  974.  
  975. } else if (data.error||null) {
  976. //check for session expired
  977. if ((data.error.message||"").find("Session has expired")){
  978. //session expired, get a new token
  979. Graph.authToken="";
  980. params["retries_expToken"]=(params["retries_expToken"])?params["retries_expToken"]+1:1; //count retries
  981. if (params["retries_expToken"]<3) {
  982. Graph.requestAuthCodeB(function(){Graph.fetchPosts(params);} );
  983. } else log("Graph.fetchPosts: cannot refresh expired fb auth token",{level:3});
  984. }
  985. else if (data.error.message||null) log("Graph.fetchPosts: "+data.error.message,{level:3});
  986.  
  987. } else log("Graph.fetchPosts: response was unrecognized",{level:3});
  988. data=null;
  989. } catch (e){log("Graph.fetchPosts: response error: "+e+": "+response);}
  990. } else log("Graph.fetchPosts: response was empty",{level:3});
  991. if(req)req=null;
  992. }catch(e){log("Graph.fetchPosts.onload: "+e);}},
  993.  
  994. onabort: function(response) {try{
  995. //remove the memory that a request is out
  996. var r = Graph.matchRequest(params);
  997. if (r!=-1) Graph.requests.remove(r);
  998. log("Graph.fetchPosts: aborted: "+response.responseText);
  999. if(req)req=null;
  1000. }catch(e){log("Graph.fetchPosts.onabort: "+e);}},
  1001.  
  1002. ontimeout: function(response) {try{
  1003. //remove the memory that a request is out
  1004. params.timeouts++;
  1005. var r = Graph.matchRequest(params);
  1006. if (r!=-1) Graph.requests.remove(r);
  1007. log("Graph.fetchPosts: timeout: retry="+(params.timeouts<3)+", "+response.responseText);
  1008. if(req)req=null;
  1009. if (params.timeouts<3) Graph.fetchPosts(params);
  1010. }catch(e){log("Graph.fetchPosts.ontimeout: "+e);}},
  1011.  
  1012. onerror: function(response) {try{
  1013. //remove the memory that a request is out
  1014. var r = Graph.matchRequest(params);
  1015. if (r!=-1) Graph.requests.remove(r);
  1016. log("Graph.fetchPosts: error: "+response.responseText);
  1017. if(req)req=null;
  1018. }catch(e){log("Graph.fetchPosts.onerror: "+e);}}
  1019. });
  1020. }catch(e){log("Graph.fetchPosts: "+e);}},
  1021. };
  1022.  
  1023. this.Graph2 = {
  1024. postData : {},
  1025. currentUser : {
  1026. authToken : null,
  1027. name : null,
  1028. id : null,
  1029. alias : null
  1030. },
  1031. friends : {},
  1032. friendLists : {},
  1033. groups : [],
  1034.  
  1035. fetchTimeout: 30,
  1036. getGraphExplorerAuthToken : function(callback){try{
  1037. //log("Graph.requestAuthCode()");
  1038. var req; req=GM_xmlhttpRequest({
  1039. method: "GET",
  1040. url: "http://developers.facebook.com/docs/reference/api/examples/",
  1041. timeout: Graph2.fetchTimeout*1000,
  1042. onload: function(response) {try{
  1043. var test=response.responseText;
  1044. var searchString='<a href="https://graph.facebook.com/me/home?access_token=';
  1045. var auth = test.indexOf(searchString),authEnd;
  1046. if (auth!=-1) {
  1047. authEnd = test.indexOf('">',auth);
  1048. var authCode = (test.substring(auth+(searchString.length), authEnd));
  1049. Graph2.currentUser.authToken = authCode;
  1050. log("Graph2.getGraphExplorerAuthToken: got token");
  1051. } else {
  1052. log("Graph2.getGraphExplorerAuthToken: "+response.responseText,{level:3});
  1053. }
  1054. if (callback) setTimeout(callback,0);
  1055. }catch(e){log("Graph2.getGraphExplorerAuthToken.onload: "+e);}},
  1056. onerror: function(response) {try{
  1057. Graph2.currentUser.authToken="";
  1058. log("Graph2.getGraphExplorerAuthToken: error:"+response.responseText+"\n.",{level:3});
  1059. }catch(e){log("Graph2.getGraphExplorerAuthToken.onerror: "+e);}},
  1060. onabort: function(response) {try{
  1061. Graph2.currentUser.authToken="";
  1062. log("Graph2.getGraphExplorerAuthToken: Request aborted",{level:3});
  1063. }catch(e){log("Graph2.getGraphExplorerAuthToken.onabort: "+e);}},
  1064. ontimeout: function(response) {try{
  1065. Graph2.currentUser.authToken="";
  1066. log("Graph.getGraphExplorerAuthToken: Request timeout",{level:3});
  1067. }catch(e){log("Graph2.getGraphExplorerAuthToken.ontimeout: "+e);}}
  1068. });
  1069. }catch(e){log("Graph2.getGraphExplorerAuthToken: "+e);}},
  1070. getAuthToken: function (callback){try{
  1071. getGraphExplorerAuthToken(callback);
  1072. }catch(e){log("Graph.getAuthToken: "+e);}},
  1073.  
  1074. likePost: function(params){try{
  1075. /*
  1076. postID
  1077. callback
  1078. post
  1079. responseText <--passback
  1080. */
  1081. var req; req=GM_xmlhttpRequest({
  1082. method: "POST",
  1083. url: "https://graph.facebook.com/"+params.postID+"/likes?access_token="+Graph2.currentUser.authToken,
  1084. timeout: Graph2.fetchTimeout*1000,
  1085. onload: function(response) {try{
  1086. params.responseText = response.responseText
  1087. if (response.responseText=="true") {
  1088. if (params.callback) params.callback(params.post);
  1089. } else {
  1090. //log(response.responseText);
  1091. //hande in whatever called this function
  1092. }
  1093. }catch(e){log("Graph2.likePost.onload: "+e);}},
  1094. onerror: function(response) {try{
  1095. params.responseText = response.responseText
  1096. }catch(e){log("Graph2.likePost.onerror: "+e);}},
  1097. onabort: function(response) {try{
  1098. params.responseText = response.responseText
  1099. }catch(e){log("Graph2.likePost.onabort: "+e);}},
  1100. ontimeout: function(response) {try{
  1101. params.responseText = response.responseText
  1102. }catch(e){log("Graph2.likePost.ontimeout: "+e);}}
  1103. });
  1104. }catch(e){log("Graph2.likePost: "+e);}},
  1105.  
  1106. unlikePost: function(params){try{
  1107. /*
  1108. postID
  1109. callback
  1110. post
  1111. responseText <--passback
  1112. */
  1113. var req; req=GM_xmlhttpRequest({
  1114. method: "DELETE",
  1115. url: "https://graph.facebook.com/"+params.postID+"/likes?access_token="+Graph2.currentUser.authToken,
  1116. timeout: Graph2.fetchTimeout*1000,
  1117. onload: function(response) {try{
  1118. params.responseText = response.responseText
  1119. if (params.callback) params.callback(params.post);
  1120. }catch(e){log("Graph2.unlikePost.onload: "+e);}},
  1121. onerror: function(response) {try{
  1122. params.responseText = response.responseText
  1123. }catch(e){log("Graph2.unlikePost.onerror: "+e);}},
  1124. onabort: function(response) {try{
  1125. params.responseText = response.responseText
  1126. }catch(e){log("Graph2.unlikePost.onabort: "+e);}},
  1127. ontimeout: function(response) {try{
  1128. params.responseText = response.responseText
  1129. }catch(e){log("Graph2.unlikePost.ontimeout: "+e);}}
  1130. });
  1131. }catch(e){log("Graph2.unlikePost: "+e);}},
  1132.  
  1133. commentPost: function(params){try{
  1134. /*
  1135. postID
  1136. callback
  1137. post
  1138. comment
  1139. responseText <--passback
  1140. */
  1141. var req; req=GM_xmlhttpRequest({
  1142. method: "POST",
  1143. url: "https://graph.facebook.com/"+params.postID+"/comments?access_token="+Graph2.currentUser.authToken+"&message="+params.comment,
  1144. timeout: Graph2.fetchTimeout*1000,
  1145. onload: function(response) {try{
  1146. params.responseText = response.responseText
  1147. if (response.responseText=="true") {
  1148. if (params.callback) params.callback(params.post);
  1149. } else {
  1150. //log(response.responseText);
  1151. }
  1152. }catch(e){log("Graph2.commentPost.onload: "+e);}},
  1153. onerror: function(response) {try{
  1154. params.responseText = response.responseText
  1155. }catch(e){log("Graph2.commentPost.onerror: "+e);}},
  1156. onabort: function(response) {try{
  1157. params.responseText = response.responseText
  1158. }catch(e){log("Graph2.commentPost.onabort: "+e);}},
  1159. ontimeout: function(response) {try{
  1160. params.responseText = response.responseText
  1161. }catch(e){log("Graph2.commentPost.ontimeout: "+e);}}
  1162. });
  1163. }catch(e){log("Graph2.commentPost: "+e);}},
  1164. getCurrentUser : function(params){try{
  1165. /*
  1166. retires_noToken <-- counter for retries without successfully finding the token
  1167. responseText <--passback
  1168. */
  1169. Graph2.getUser({
  1170. userID:"me",
  1171. callback:function(){Graph2.procCurrentUser(params);}
  1172. });
  1173. }catch(e){log("Graph2.getCurrentUser: "+e);}},
  1174. procCurrentUser : function(params){try{
  1175. /*
  1176. responseText
  1177. */
  1178. var data = JSON.parse(params.responseText);
  1179. if (data["id"]||null){
  1180. //expected data exists
  1181. Graph2.currentUser.id=data["id"||null];
  1182. //Graph2.currentUser.alias=(data["username"]||null);
  1183. Graph2.currentUser.name=(data["name"]||null);
  1184. Graph2.currentUser.timezone=(data["timezone"]||null);
  1185. Graph2.currentUser.locale=(data["locale"]||null);
  1186.  
  1187. if (params.callback) setTimeout(function(){params.callback(Graph2.currentUser);},0);
  1188. } else if (data["error"]||null) {
  1189. var emsg=data.error.message||null;
  1190. //check for session expired
  1191. if (emsg.find("Session has expired")||emsg.find("session is invalid")){
  1192. //session expired or logged out, get a new token
  1193. Graph2.currentUser.authToken="";
  1194. params["retries_expToken"]=(params["retries_expToken"])?params["retries_expToken"]+1:1; //count retries
  1195. if (params["retries_expToken"]<3) {
  1196. setTimeout(function(){Graph2.getAuthToken({callback:Graph2.getCurrentUser});},0);
  1197. } else log("Graph2.procCurrentUser: cannot refresh expired fb auth token",{level:3});
  1198. } else if (emsg) log("Graph2.procCurrentUser: "+emsg,{level:3});
  1199.  
  1200. } else log("Graph2.procCurrentUser: response was unrecognized",{level:3});
  1201. }catch(e){log("Graph2.procCurrentUser: "+e);}},
  1202. getUser : function(params){try{
  1203. /*
  1204. userID <-- "me" for current user
  1205. callback
  1206. retires_noToken <-- counter for retries without successfully finding the token
  1207. responseText <--passback
  1208. */
  1209. //log("Graph.getUser()");
  1210. params=params || {};
  1211. if (!Graph2.currentUser.authToken) {
  1212. params["retries_noToken"]=(params["retries_noToken"])?params["retries_noToken"]+1:1; //count retries
  1213. if (params["retries_noToken"]<3) {
  1214. Graph2.getAuthToken(function(){Graph2.getUser(params);} );
  1215. } else {
  1216. log("Graph2.getUser: cannot get new fb auth token",{level:3});
  1217. return;
  1218. }
  1219. return;
  1220. }
  1221. var URL="https://graph.facebook.com/"+params.userID+"?access_token="+Graph2.currentUser.authToken;
  1222. var req; req=GM_xmlhttpRequest({
  1223. method: "GET",
  1224. url: URL,
  1225. timeout: Graph2.fetchTimeout*1000,
  1226. onload: function(response) {try{
  1227. if (response){
  1228. params.responseText = response.responseText;
  1229. } else log("Graph2.getUser: response was empty",{level:3});
  1230. }catch(e){log("Graph2.getUser.onload: "+e);}},
  1231.  
  1232. onabort: function(response) {try{
  1233. params.responseText = response.responseText;
  1234. log("Graph2.getUser: Request aborted");
  1235. }catch(e){log("Graph2.getUser.onabort: "+e);}},
  1236. ontimeout: function(response) {try{
  1237. params.responseText = response.responseText;
  1238. log("Graph2.getUser: Request timeout");
  1239. }catch(e){log("Graph2.getUser.ontimeout: "+e);}},
  1240.  
  1241. onerror: function(response) {try{
  1242. params.responseText = response.responseText;
  1243. if (response.responseText=="") {
  1244. log("Graph2.getUser: responseText was empty. Check to make sure your browser is online.", {level:5});
  1245. } else {
  1246. log("Graph2.getUser: Request error");
  1247. }
  1248. }catch(e){log("Graph2.getUser.onerror: "+e);}}
  1249. });
  1250. }catch(e){log("Graph2.getUser: "+e);}},
  1251. getPost : function() {
  1252. },
  1253. getPosts : function() {
  1254. },
  1255. getIsFriend : function(userId) {
  1256. return ((Graph2.friends[userId]||null)!=null);
  1257. },
  1258. getFriends : function(params) {try{
  1259. params=params || {};
  1260. if (!Graph2.currentUser.authToken) {
  1261. params["retries_noToken"]=(params["retries_noToken"])?params["retries_noToken"]+1:1; //count retries
  1262. if (params["retries_noToken"]<3) {
  1263. Graph2.getAuthToken(function(){Graph2.getFriends(params);} );
  1264. } else {
  1265. log("Graph2.getFriends: cannot get new fb auth token",{level:3});
  1266. return;
  1267. }
  1268. return;
  1269. }
  1270. var URL="https://graph.facebook.com/me/friends?limit=5000&access_token="+Graph2.currentUser.authToken;
  1271. var req; req=GM_xmlhttpRequest({
  1272. method: "GET",
  1273. url: URL,
  1274. timeout: Graph2.fetchTimeout*1000,
  1275. onload: function(response) {try{
  1276. if (response){
  1277. params.responseText = response.responseText;
  1278. setTimeout(function(){Graph2.procFriends(params);},0);
  1279. } else log("Graph2.getFriends: response was empty",{level:3});
  1280. }catch(e){log("Graph2.getFriends.onload: "+e);}},
  1281.  
  1282. onabort: function(response) {try{
  1283. params.responseText = response.responseText;
  1284. log("Graph2.getFriends: Request aborted");
  1285. }catch(e){log("Graph2.getFriends.onabort: "+e);}},
  1286. ontimeout: function(response) {try{
  1287. params.responseText = response.responseText;
  1288. log("Graph2.getFriends: Request timeout");
  1289. }catch(e){log("Graph2.getFriends.ontimeout: "+e);}},
  1290.  
  1291. onerror: function(response) {try{
  1292. params.responseText = response.responseText;
  1293. log("Graph2.getFriends: Request error");
  1294. }catch(e){log("Graph2.getFriends.onerror: "+e);}}
  1295. });
  1296. }catch(e){log("Graph2.getFriends: "+e);}},
  1297.  
  1298. procFriends : function(params){try{
  1299. /*
  1300. responseText
  1301. */
  1302. var data = JSON.parse(params.responseText);
  1303. if (data["data"]||null){
  1304.  
  1305. //index friend user data
  1306. for (var user in data.data) {
  1307. Graph2.friends[user.id] = user;
  1308. }
  1309. if (params.callback) setTimeout(function(){params.callback(Graph2.friends);},0);
  1310. } else log("Graph2.procFriends: response was unrecognized",{level:3});
  1311. }catch(e){log("Graph2.procFriends: "+e);}},
  1312. getIsUserInFriendList : function() {
  1313. },
  1314. getFriendLists : function(params) {try{
  1315. params=params || {};
  1316. if (!Graph2.currentUser.authToken) {
  1317. params["retries_noToken"]=(params["retries_noToken"])?params["retries_noToken"]+1:1; //count retries
  1318. if (params["retries_noToken"]<3) {
  1319. Graph2.getAuthToken(function(){Graph2.getFriendLists(params);} );
  1320. } else {
  1321. log("Graph2.getFriendLists: cannot get new fb auth token",{level:3});
  1322. return;
  1323. }
  1324. return;
  1325. }
  1326. var URL="https://graph.facebook.com/me/friendlists?limit=5000&access_token="+Graph2.currentUser.authToken;
  1327. var req; req=GM_xmlhttpRequest({
  1328. method: "GET",
  1329. url: URL,
  1330. timeout: Graph2.fetchTimeout*1000,
  1331. onload: function(response) {try{
  1332. if (response){
  1333. params.responseText = response.responseText;
  1334. setTimeout(function(){Graph2.procFriend=Lists(params);},0);
  1335. } else log("Graph2.getFriendLists: response was empty",{level:3});
  1336. }catch(e){log("Graph2.getFriendLists.onload: "+e);}},
  1337.  
  1338. onabort: function(response) {try{
  1339. params.responseText = response.responseText;
  1340. log("Graph2.getFriendLists: Request aborted");
  1341. }catch(e){log("Graph2.getFriendLists.onabort: "+e);}},
  1342. ontimeout: function(response) {try{
  1343. params.responseText = response.responseText;
  1344. log("Graph2.getFriendLists: Request timeout");
  1345. }catch(e){log("Graph2.getFriendLists.ontimeout: "+e);}},
  1346.  
  1347. onerror: function(response) {try{
  1348. params.responseText = response.responseText;
  1349. log("Graph2.getFriendLists: Request error");
  1350. }catch(e){log("Graph2.getFriendLists.onerror: "+e);}}
  1351. });
  1352. }catch(e){log("Graph2.getFriendLists: "+e);}},
  1353. procFriendLists : function(params){try{
  1354. /*
  1355. responseText
  1356. */
  1357. var data = JSON.parse(params.responseText);
  1358. if (data["data"]||null){
  1359.  
  1360. //index friend user data
  1361. for (var list in data.data) {
  1362. Graph2.friendLists[list.id] = list;
  1363. }
  1364. if (params.callback) setTimeout(function(){params.callback(Graph2.friendLists);},0);
  1365. } else log("Graph2.procFriendLists: response was unrecognized",{level:3});
  1366. }catch(e){log("Graph2.procFriendLists: "+e);}}
  1367. }
  1368. log("Graph initialized");
  1369. })();