root/trunk/website/org/sweettweets/SweetTweets.cfc @ 21

Revision 5, 14.7 kB (checked in by DanWilson, 17 years ago)

Initial Commit Of ModelGlue? Website (upgrade to blogcfc 511)

Line 
1<!---
2LICENSE INFORMATION:
3
4Copyright 2008, Adam Tuttle
5 
6Licensed under the Apache License, Version 2.0 (the "License"); you may not
7use this file except in compliance with the License.
8
9You may obtain a copy of the License at
10
11        http://www.apache.org/licenses/LICENSE-2.0
12       
13Unless required by applicable law or agreed to in writing, software distributed
14under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
15CONDITIONS OF ANY KIND, either express or implied. See the License for the
16specific language governing permissions and limitations under the License.
17
18VERSION INFORMATION:
19
20This file is part of SweetTweetsCFC (1.4).
21http://sweettweetscfc.riaforge.org/
22--->
23<!---
24        Author: Adam Tuttle
25        Website: http://fusiongrokker.com
26        Instructions: See example.cfm (and other examples) for usage
27--->
28<cfcomponent output="false">
29       
30        <cfset variables.urlService = ""/>
31        <cfset variables.jsonService = ""/>
32        <cfset variables.cacheLocation = "application"/>
33       
34        <cffunction name="init" output="false">
35                <cfargument name="useLocalCache" type="boolean" default="true"/>
36                <!--- save cache location --->
37                <cfif arguments.useLocalCache>
38                        <cfset variables.cacheLocation = "variables"/>
39                <cfelse>
40                        <cfset variables.cacheLocation = "application" />
41                </cfif>
42                <!--- Using shrinkURL from Andy Matthews: http://shrinkurl.riaforge.org/ --->
43                <cfset variables.urlService = createObject("component","shrinkURL").init()/>
44                <!--- Using JSONUtil from Nathan Mische: http://jsonutil.riaforge.org/ --->
45                <cfset variables.jsonService = createObject("component","JSONUtil").init()/>
46                <cfreturn this/>
47        </cffunction>
48       
49        <!--- public functions --->
50        <cffunction name="getTweetbacks" access="public" output="false" returntype="array">
51                <cfargument name="uri" type="string" required="true"/>
52                <cfscript>
53                        var local = structNew();
54                        var cacheKey = '';
55                       
56                        //first some business -- if being called remotely (ajax), jsonService and urlService will be blank! :(
57                        if (isSimpleValue(variables.urlService)){variables.urlService = createObject("component", "shrinkURL").init();}
58                        if (isSimpleValue(variables.jsonService)){variables.jsonService = createObject("component", "JSONUtil").init();}
59
60                        //strip any bookmarks from the url
61                        arguments.uri = listFirst(arguments.uri,'##');
62                       
63                        //setup cache
64                        cacheKey = hash(arguments.uri);
65                        setupCache(cacheKey);
66                       
67                        //check tweetback cache, updates every 5 minutes at most
68                        if (not tweetCacheExpired(cacheKey)){
69                                local.tweets = getTweetCache(cacheKey);
70                        }else{
71                                local.thisSearch = getTweetSearchUrl(arguments.uri);
72                                local.shortened = getShortUrls(arguments.uri);
73
74                                local.tweets = makeTwitterSearchRequest(local.thisSearch).results;
75                                local.tweets = killImpostors(local.tweets,local.shortened);
76                                local.tweets = cleanup(local.tweets);
77
78                                //cache tweets for 5 minutes
79                                setTweetCache(cacheKey, local.tweets, 5);
80                        }
81
82                        return local.tweets;
83                </cfscript>
84        </cffunction>
85        <cffunction name="debug" access="public" output="true" returntype="any">
86                <cfargument name="uri" type="string" required="true"/>
87                <cfscript>
88                        var local = structNew();
89                        var cacheKey = '';
90
91                        //strip any bookmarks from the url
92                        arguments.uri = listFirst(arguments.uri,'##');
93                       
94                        //setup cache
95                        cacheKey = hash(arguments.uri);
96                        setupCache(cacheKey);
97
98                        //use services
99                        local.thisSearch = getTweetSearchUrl(arguments.uri);
100                        local.shortened = getShortUrls(arguments.uri);
101                        local.tweets = makeTwitterSearchRequest(local.thisSearch).results;
102                        local.tweets = killImpostors(local.tweets,local.shortened);
103                        local.tweets = cleanup(local.tweets);
104
105                        dump(local,true);
106                </cfscript>
107        </cffunction>
108        <cffunction name="getTweetbacksHTML" access="remote" output="false" returntype="string">
109                <cfargument name="uri" type="string" required="true"/>
110                <cfargument name="limit" type="numeric" required="false" default="100" hint="Number of tweets to display, recent gets priority. 0 = unlimited"/>
111                <cfscript>
112                        var local = structNew();
113                        local.dsp = structNew();
114
115                        local.tweets = getTweetbacks(arguments.uri);
116                        local.searchUrl = replace(getTweetSearchUrl(arguments.uri), ".json", "");//instead of linking to json, link to search results page
117                        local.tweetCount = arrayLen(local.tweets);
118                        local.limit = min(arguments.limit, local.tweetcount);
119                        if (local.limit eq 0){local.limit=local.tweetcount;}
120                       
121                        //define header
122                        if (local.tweetcount eq 0){
123                                local.dsp.header = "<h3>No Tweetbacks</h3>";
124                        }else{
125                                local.dsp.header = "<h3>#arrayLen(local.tweets)# Tweetbacks</h3>";
126                                if (local.tweetcount eq 1){local.dsp.header=replace(local.dsp.header,"Tweetbacks","Tweetback");}
127                        }
128                        //define view-all link
129                        if (local.tweetcount lte local.limit or local.limit eq 0){
130                                local.dsp.allLink = "";
131                        }else{
132                                local.dsp.allLink = "Showing #local.limit# most recent - <a id='viewAllTweetbacks' href='#local.searchUrl#'>View All Tweetbacks</a>";
133                        }
134                </cfscript>
135                <!---streamlined html to be as small as possible since it very well might be returned via ajax--->
136                <cfsavecontent variable="local.tweetbackHTML"><cfoutput><div id="tweetbacks">#local.dsp.header##local.dsp.allLink#<ul><cfloop from="1" to="#local.limit#" index="local.t"><li style="clear:left;"><img src="#local.tweets[local.t].profile_image_url#" align="left" vspace="2" hspace="4"/> <a href="http://twitter.com/#local.tweets[local.t].from_user#" style="background:none;"><strong>#local.tweets[local.t].from_user#</strong></a> <span class="tweetback_tweet">#local.tweets[local.t].text#</span> <span class="tweetback_timestamp"><a href="http://twitter.com/#local.tweets[local.t].from_user#/statuses/#local.tweets[local.t].id#">#local.tweets[local.t].created_at#</a></span></li></cfloop></ul></div></cfoutput></cfsavecontent>
137                <cfreturn local.tweetbackHTML/>
138        </cffunction>
139       
140        <!--- data functions --->
141        <cffunction name="getShortUrls" access="private" output="false" returnType="struct">
142                <cfargument name="uri" type="string" required="true"/>
143                <cfscript>
144                        var local = StructNew();
145                        local.shortened = structNew();
146                        //cligs
147                        local.cligsParams = StructNew();
148                        local.cligsParams['appid'] = urlEncodedFormat('http://sweettweetscfc.riaforge.org');
149                        local.shortened.cligs = urlService.shrink('cligs',arguments.uri,local.cligsParams);
150                        if (len(trim(local.shortened.cligs)) eq 0){
151                                structDelete(local.shortened, "cligs");
152                        }
153                        //simple services
154                        local.shortened.isgd = urlService.shrink('isgd',arguments.uri);
155                        local.shortened.tinyurl = urlService.shrink('tinyurl', arguments.uri);
156                        local.shortened.hexio = urlService.shrink('hexio', arguments.uri);
157                        return local.shortened;
158                </cfscript>
159        </cffunction>
160        <cffunction name="getTweetSearchUrl" access="private" output="false" returnType="string">
161                <cfargument name="uri" type="string" required="true"/>
162                <cfscript>
163                        var local = structNew();
164                        var cacheKey = hash(arguments.uri);
165                        //shortened url cache never expires
166                        if (urlCacheExists(cacheKey)){
167                                local.shortened = getUrlCache(cacheKey);
168                        }else{
169                                //get shortened versions of the url
170                                local.shortened = getShortUrls(arguments.uri);
171                                //and cache the result
172                                setUrlCache(cacheKey, local.shortened);
173                        }
174
175                        //compile twitter search url
176                        local.api = 'http://search.twitter.com/search.json?rpp=100&q=&ors=';
177                        local.thisSearch = local.api
178                                & urlEncodedFormat(local.shortened.isgd) & '+'
179                                & urlEncodedFormat(local.shortened.cligs) & '+'
180                                & urlEncodedFormat(local.shortened.tinyurl) & '+'
181                                & urlEncodedFormat(local.shortened.hexio);
182                       
183                        return local.thisSearch;
184                </cfscript>
185        </cffunction>
186        <cffunction name="makeTwitterSearchRequest" access="private" output="false" returnType="any">
187                <cfargument name="req" type="String" required="true"/>
188                <cfset var result = ""/>
189                <cfhttp url="#arguments.req#" method="get" result="result" useragent="SweetTweets plugin v0.0 for Mango Blog|http://fusiongrokker.com"></cfhttp>
190                <cftry>
191                        <cfset result = jsonService.deserialize(result.fileContent.toString())/>
192                        <cfcatch type="any"><!--- catch errors thrown by jsonService (likely problem w/twitter search - down,etc), return empty set --->
193                                <cfset result = StructNew()/>
194                                <cfset result.results = arrayNew(1)/>
195                        </cfcatch>
196                </cftry>
197                <cfreturn result />
198        </cffunction>
199        <cffunction name="cleanup" access="private" output="false" returnType="array">
200                <cfargument name="tweets" type="array" required="true"/>
201                <cfscript>
202                        var local = structNew();
203                        var i = 0;
204                        local.linkRegex = "((https?|s?ftp|ssh)\:\/\/[^""\s\<\>]*[^.,;'"">\:\s\<\>\)\]\!])";
205                        local.atRegex = "@([_a-z0-9]+)";
206                        local.hashRegex = "##([_a-z0-9]+)";
207                        for (i=1;i lte arrayLen(arguments.tweets);i=i+1){
208                                //fix links
209                                arguments.tweets[i].text = REReplaceNoCase(arguments.tweets[i].text,local.linkRegex,"<a href='\1'>\1</a>","all");
210                                arguments.tweets[i].text = REReplaceNoCase(arguments.tweets[i].text,local.atRegex,"<a href='http://twitter.com/\1'>@\1</a>","all");
211                                arguments.tweets[i].text = REReplaceNoCase(arguments.tweets[i].text,local.hashRegex,"<a href='http://www.hashtags.org/tag/\1'>##\1</a>");
212                                //remove ugly stuff from timestamp
213                                arguments.tweets[i].created_at = Replace(arguments.tweets[i].created_at, "+0000", "");
214                        }
215                        return arguments.tweets;
216                </cfscript>
217        </cffunction>
218        <cffunction name="killImpostors" access="private" output="false" returnType="array">
219                <cfargument name="data" required="true" type="array"/>
220                <cfargument name="shorties" required="true" type="struct"/>
221                <cfscript>
222                        //this function removes false positives returned because search is case-INsensitive, but shortened url's are case-sensitive
223                        var i = 0;
224                        var j = 0;
225                        var keyNames = structKeyList(shorties);
226                        var impostor = true;
227                        for (i=1;i lte arrayLen(data);i=i+1){
228                                impostor = true;
229                                for (j=1;j lte listLen(keyNames);j=j+1){
230                                        if (find(shorties[listGetAt(keyNames,j)],data[i].text)){
231                                                impostor = false;
232                                                break;
233                                        }
234                                }
235                                if (impostor){
236                                        arrayDeleteAt(data,i);
237                                        i=i-1;
238                                }
239                        }
240                        return data;
241                </cfscript>
242        </cffunction>
243
244        <!--- caching functions --->
245        <cffunction name="setupCache" access="private" output="false" returnType="void">
246                <cfargument name="cacheKey" type="string" required="true" />
247                <cfscript>
248                        if (variables.cacheLocation eq "application"){
249                                if (not structKeyExists(application, "SweetTweetCache")){application.SweetTweetCache=StructNew();}
250                                if (not structKeyExists(application.sweetTweetCache, "urls")){application.sweetTweetCache.urls=StructNew();}
251                                if (not structKeyExists(application.sweetTweetCache, "tweetbacks")){application.sweetTweetCache.tweetbacks=StructNew();}
252                                if (not structKeyExists(application.sweetTweetCache.tweetbacks, arguments.cacheKey)){application.sweetTweetCache.tweetbacks[arguments.cacheKey]=StructNew();}
253                        }else{
254                                if (not structKeyExists(variables, "SweetTweetCache")){variables.SweetTweetCache=StructNew();}
255                                if (not structKeyExists(variables.sweetTweetCache, "urls")){variables.sweetTweetCache.urls=StructNew();}
256                                if (not structKeyExists(variables.sweetTweetCache, "tweetbacks")){variables.sweetTweetCache.tweetbacks=StructNew();}
257                                if (not structKeyExists(variables.sweetTweetCache.tweetbacks, arguments.cacheKey)){variables.sweetTweetCache.tweetbacks[arguments.cacheKey]=StructNew();}
258                        }
259                </cfscript>
260        </cffunction>
261        <cffunction name="tweetCacheExpired" access="private" output="false" returnType="boolean">
262                <cfargument name="cacheKey" type="string" required="true"/>
263                <cfscript>
264                        if (variables.cacheLocation eq "application"){
265                                return (not structKeyExists(application.sweetTweetCache.tweetbacks[arguments.cacheKey], "timeout") or
266                                                dateCompare(now(), application.sweetTweetCache.tweetbacks[arguments.cacheKey].timeout) eq 1);
267                        }else{
268                                return (not structKeyExists(variables.sweetTweetCache.tweetbacks[arguments.cacheKey], "timeout") or
269                                                dateCompare(now(), variables.sweetTweetCache.tweetbacks[arguments.cacheKey].timeout) eq 1);
270                        }
271                </cfscript>
272        </cffunction>
273        <cffunction name="getTweetCache" access="private" output="false" returnType="array">
274                <cfargument name="cacheKey" type="string" required="true"/>
275                <cfscript>
276                        if (variables.cacheLocation eq "application"){
277                                return application.sweetTweetCache.tweetbacks[arguments.cacheKey].tweets;
278                        }else{
279//dump(variables.sweetTweetCache,true);
280                                return variables.sweetTweetCache.tweetbacks[arguments.cacheKey].tweets;
281                        }
282                </cfscript>
283        </cffunction>
284        <cffunction name="setTweetCache" access="private" output="false" returnType="void">
285                <cfargument name="cacheKey" type="string" required="true"/>
286                <cfargument name="data" type="array" required="true"/>
287                <cfargument name="timeout" type="any" required="true"/>
288                <cfscript>
289                        if (variables.cacheLocation eq "application"){
290                                application.sweetTweetCache.tweetbacks[arguments.cacheKey].tweets = arguments.data;
291                                application.sweetTweetCache.tweetbacks[arguments.cacheKey].timeout = dateAdd("n",arguments.timeout,now());
292                        }else{
293                                variables.sweetTweetCache.tweetbacks[arguments.cacheKey].tweets = arguments.data;
294                                variables.sweetTweetCache.tweetbacks[arguments.cacheKey].timeout = dateAdd("n",arguments.timeout,now());
295                        }
296                </cfscript>
297        </cffunction>
298        <cffunction name="urlCacheExists" access="private" output="false" returnType="boolean">
299                <cfargument name="cacheKey" type="string" required="true"/>
300                <cfscript>
301                        if (variables.cacheLocation eq "application"){
302                                return (structKeyExists(application.SweetTweetCache.urls, arguments.cacheKey));
303                        }else{
304                                return (structKeyExists(variables.SweetTweetCache.urls, arguments.cacheKey));
305                        }
306                </cfscript>
307        </cffunction>
308        <cffunction name="getUrlCache" access="private" output="false" returnType="struct">
309                <cfargument name="cacheKey" type="string" required="true"/>
310                <cfscript>
311                        if (variables.cacheLocation eq "application"){
312                                return application.sweetTweetCache.urls[arguments.cacheKey];
313                        }else{
314                                return variables.sweetTweetCache.urls[arguments.cacheKey];
315                        }
316                </cfscript>
317        </cffunction>
318        <cffunction name="setUrlCache" access="private" output="false" returnType="void">
319                <cfargument name="cacheKey" type="string" required="true"/>
320                <cfargument name="data" type="struct" required="true"/>
321                <cfscript>
322                        if (variables.cacheLocation eq "application"){
323                                application.sweetTweetCache.urls[arguments.cacheKey] = arguments.data;
324                        }else{
325                                variables.sweetTweetCache.urls[arguments.cacheKey] = arguments.data;
326                        }
327                </cfscript>
328        </cffunction>
329
330        <cffunction name="dump" access="private" output="false">
331                <cfargument name="var" required="true"/>
332                <cfargument name="abort" default="false"/>
333                <cfdump var="#arguments.var#">
334                <cfif arguments.abort>
335                        <cfabort>
336                </cfif>
337        </cffunction>
338       
339</cfcomponent>
Note: See TracBrowser for help on using the browser.