Klipfolio Inc. Copyright © 2002-2009 Klipfolio Inc. support@klipfolio.com http://www.klipfolio.com/ YouTube 3.2 youtube_834674 2008.12.09 See the most recently added, viewed, or discussed videos right now on YouTube. youtube you tube video view http://www.youtube.com/ http://www.serence.com/serence_klips/pics/youtube_icon.png http://www.serence.com/serence_klips/pics/youtube_banner.gif http://www.serence.com/serence_klips/youtube.klip 60 -- -- true 5899 Looking for videos... No videos to display. 5892) { // If we are upgrading from one of the versions of this Klip that // used the frame style, clear the items so that they will be reloaded // using the old style Items.clear(true); } } } function onLoad() { _t( "onLoad()" ); var style = ""; if(KlipFolio.build <= 5896) { // This is version 4 or earlier, so use the old style style = "channel > title, feed title {type: scratch; name: 'Channel Title';}" + "channel image url {type: scratch; name: 'Channel Image';}" + "item, entry {type: item; definition: 'visibletitle,matchtitle,source,link,storyimage,description,sourcerow,banner,pubdate,guid2';}" + "storyimage {type: image; noterow: 1; itemcol: 1; height: 2; notelabel: false; key: exclude; name: 'storyimage'; valign: middle; fit: zoom; width: 3;}" + "description, note, content:encoded, content {type: text; noterow: 4; notelabel: false; content: cdata; order: 1; key: exclude; name: 'description';}" + "link {type: link; key: exclude; name: 'link'; order: 1;}" + "guid {type: text; key: include; name: 'guid2';}" + "pubDate, dc:date, modified {type: pubdate; key: exclude; name: 'pubdate';}" + "banner {type: image; noterow: 10; notelabel: false; key: exclude;}" + "sourcerow {type: text; noterow: 9; wrap: false; key: exclude; label: 'Source';}" + "source {type: text; itemcol: 3; wrap: false; key: exclude;}" + "title {type: text; key: include; name: 'matchtitle';}" + "visibletitle {itemcol: 2; maxwidth: 14; noterow: 2; notelabel: false; emphasis: strong; key: exclude; priority: 1;}"; if(Prefs.getPref("PrevBuild") > 5896) { // We are downgrading to KlipFolio version 4, so clear the items. Items.clear(true); } } else { // This is version 5 or later, so use the new card layout style = "channel > title, feed title {type: scratch; name: 'Channel Title';}" + "channel image url {type: scratch; name: 'Channel Image';}" + "item, entry {type: item; layout: card; definition: 'visibletitle,matchtitle,source,sourcerow,link,storyimage,description,visibledesc,banner,pubDate,guid,author';}" + "storyimage {type: image; noterow: 1; itemcol: 1; height: 3; notelabel: false; key: exclude; name: 'storyimage'; valign: middle; fit: zoom; width: 3; label: 'Preview';}" + "description, note, content:encoded, content {type: text; noterow: 4; notelabel: false; content: cdata; key: exclude; name: 'description';}" + "link {type: link; key: exclude; name: 'link'; order: 1;}" + "guid {type: text; key: include; name: 'guid2';}" + "pubDate, dc:date, modified {type: pubdate; key: exclude; name: 'pubdate';}" + "banner {type: image; noterow: 10; notelabel: false; key: exclude;}" + "sourcerow {type: text; noterow: 9; wrap: false; key: exclude; label: 'Source';}" + "source {type: text; itemcol: 4; wrap: false; key: exclude; label: 'Category';}" + "title {type: text; key: include; name: 'matchtitle';}" + "visibletitle {itemcol: 2; maxwidth: 14; noterow: 2; notelabel: false; emphasis: strong; key: exclude; priority: 1; label: 'Video';}" + "visibledesc {itemcol: 3; key: exclude; label: 'Description';}" + "media:credit {type: text; name: 'author';}"; if(Prefs.getPref("PrevBuild") <= 5896) { // We are upgrading to KlipFolio version 5, so clear the items. Items.clear(true); } } Prefs.setPref("PrevBuild", KlipFolio.build); Engines.KlipFood.stylesheet = style; var lc_index = -1; var tab; // // Loop through all the feeds and build the Klip Setup tab // for (var i = 0; i < multiFeeds.length; i++) { if ( multiFeeds[i][URL].indexOf("-") == 0 ) { // // Got a "-" character so create a new tab for subsequent URLs // lc_index++; tab = Setup.addTab( multiFeeds[i][NAME] ); tab.addText( "Choose your sources to monitor:" ); lcSource[ lc_index ] = tab.addListControl( true, true ); lcSource[ lc_index ].onStateChange = lcSource_onStateChange; // // Every object in KlipFolio can have a custom property just by declaring it. // Here we store an index related to the entry in the array multiFeeds[] // lcSource[ lc_index ].offset = i + 1; lcSource[ lc_index ].name = multiFeeds[i][NAME]; } else { // // Add this URL to the current ListControl // var initial_state = multiFeeds[i][INITIAL_STATE]; // true or false var name = multiFeeds[i][NAME]; var url = multiFeeds[i][URL]; var checked; var prefs_name = lcSource[ lc_index ].name + "|" + name; if( Prefs.getPref( prefs_name ) == "" ) { // No initial state state = initial_state; Prefs.setPref( prefs_name, checked ); } else { // get saved checked/unchecked state state = Prefs.getPref( prefs_name ) == "true" ? true : false; } lcSource[ lc_index ].addItem( name, state ); multiFeeds[i].updated = state; } } // Add the Search tab tab = Setup.addTab("Search"); tab.addText("Show videos that contain any of the following keywords:"); g_keywords = tab.addTextField(Prefs.getPref("keywords")); tab.addText("Show videos from the following users:"); g_users = tab.addTextField(Prefs.getPref("users")); tab.addSpacer(); tab.addText("Use commas, without spaces, to separate keywords or users. For example: apple,windows,comics,xbox"); for (var i = 0; i < Items.length; ++i) { Items[i].tagged = true; // These items have already been processed } UpdatePrefs(); UpdateSearchPrefs(); // Set up callbacks to handle item creation Engines.KlipFood.onCreate = myCreate; Engines.KlipFood.onUpdate = myUpdate; // Don't autoremove items Items.autoremove = false; if (KlipFolio.build >= 5897) { Items.actions = ["Show More Videos from this User", moreUserVideos]; } if( gTrace ) // Add a debug tab in the Klip { button = tab.addButton( "Show State in Trace Window" ); button.onClick = show_state; } } function moreUserVideos(item) { var user = item.getData("author"); // Add the term to the search field if(g_users.value.length == 0) { g_users.value = user; } else { g_users.value += "," + user; } UpdateSearchPrefs(); Klip.requestRefresh(); } // // Called when a ListControl was clicked. // // Because we are refreshing the Klip in between user events, it's possible for the // user to quickly click multiple items in the list control before we get an event // from KlipFolio that the list control was updated. // // So, we keep a shadow value for each list control item called .previous_state // // We use the property .offset to find the index of this entry // function lcSource_onStateChange( index ) { _t( "Item: " + this[index] ); _t( "Offset: " + this.offset ); _t( "State: " + this.getState(index) ); var name = multiFeeds[index + this.offset][NAME]; var state = this.getState(index); _t( "You clicked on: " + name ); UpdatePrefs(); // update the state of all visible items in the list. Use the Item's name, // which is stored in .extra, as a hash lookup for Prefs.getPref() for (var i = 0; i < Items.length; ++i) { Items[i].hidden = Prefs.getPref( Items[i].extra ) == "true" ? false : true; } // // Request a refresh to update any feeds the user has changed to // now show. // // Comment out these two lines to have the user click the Refresh button in the Klip setup // userClickedListControl = true; Klip.requestRefresh(); } function UpdatePrefs() { // // Store the state of the prefs for all listControls. // for (var lc_index = 0; lc_index < lcSource.length; lc_index++) { for (var i = 0; i < lcSource[lc_index].length; i++ ) { var prefs_name = lcSource[ lc_index ].name + "|" + lcSource[lc_index][i]; Prefs.setPref( prefs_name, lcSource[lc_index].getState( i ) ); } } } function UpdateSearchPrefs() { Prefs.setPref("keywords", g_keywords.value); Prefs.setPref("users", g_users.value); } // // Mark all items in Items[] that have been marked as coming from // the feed of the given name // function items_mark( name ) { for (var i=0; i 0) { keyword_feeds = g_keywords.value.split(","); for(counter = 0; counter < keyword_feeds.length; counter++) { result = getData(("http://www.youtube.com/rss/tag/" + keyword_feeds[counter] + ".rss"), keyword_feeds[counter]); } } if(g_users.value.length > 0) { user_feeds = g_users.value.split(","); for(counter = 0; counter < user_feeds.length; counter++) { result = getData(("http://www.youtube.com/rss/user/" + user_feeds[counter] + "/videos.rss"), user_feeds[counter]); } } // Remove any items that are not being searched for any more var loopFinish = Items.length; for(counter = 0; counter < loopFinish; counter++) { // keywords if(Items[counter].getData("source").lastIndexOf("Tag") != -1) { // We've found a keyword entry - check to see if that tag is still in the search field if(g_keywords.value.lastIndexOf(Items[counter].extra) == -1) { // The tag is not in the search field, so remove the item Items.remove(counter); counter--; loopFinish--; } } } loopFinish = Items.length; for(counter = 0; counter < loopFinish; counter++) { // users if(Items[counter].getData("source").lastIndexOf("Videos by") != -1) { // We've found a user entry - check to see if that user is still in the search field if(g_users.value.lastIndexOf(Items[counter].extra) == -1) { // The tag is not in the search field, so remove the item Items.remove(counter); counter--; loopFinish--; } } } UpdateSearchPrefs(); // Clear global state return result; } // // Refresh only the items for the given URL. // function getData( url, name ) { _t( "Refreshing : " + url ); req = Engines.HTTP.newRequest (url); if ( !req.send() ) { _t( "Unable to send url" ); return false; } var data = req.response.data; if( !data.length ) { // Check if we got a "304 Not Modified message" in the headers // // true -- data has not changed since we last checked it // false -- no data for another reason, return false var re_304 = new RegExp( "304 Not Modified" ); var check = re_304.exec( req.response.headers ) != null; if ( check ) { _t( "304 NOT MODIFIED returned -- no refresh needed" ); } return( check ); } // At this point we have data, so let's refresh this source and purge // any items that are not updated // items_mark( name ); // Mark all items for this source Engines.KlipFood.process (req.response); items_purge( name ); // Delete all items not updated _t( " done" ); // Update the show of sources // var count = 0; for (var i = 0; i < Items.length; i++) { if (!Items[i].tagged) { Items[i].extra = name; Items[i].tagged = true; count++; } } _t(" Updated #: " + count ); return true; } // // The myCreate function modifies the properties of each new item that is created. // function myCreate (new_item) { _t( "myCreate()" ); if (multiFeeds.length) { var source = Klip.processEntities (Engines.KlipFood.getScratch ("Channel Title")); new_item.setData ("sourcerow", source); if (multiFeeds.length > 1) { // Remove the "YouTube :: " part of the source new_item.setData ("source", source); } new_item.setData ("banner", Klip.processEntities (Engines.KlipFood.getScratch ("Channel Image"))); // note that the replace on tags is to fix feedster's naive highlighting of search terms var data = Klip.processEntities (new_item.getData ("description")).replace (/(|<\/strong>)/g, ""); var index; var m; // // Retrieve an image from the news item and display it in the note // var imgdata = data; var done = false; while (!done && ((index = imgdata.indexOf ("')) != -1) {} if (index2 != -1) { img = m.substring (0, index2); } } } img = Klip.convertToText (img); if (img.length) { if (!imageBlacklisted (img)) { new_item.setData ("storyimage", img); done = true; } } } //while data = data.replace(/From:<\/span>/, "
From:<\/span>"); data = data.replace(/Views:<\/span>/, "
Views:<\/span>"); data = data.replace(/Time:<\/span>/, "
Time:<\/span>"); data = data.slice(0, data.lastIndexOf("More in")); data = Klip.convertToText(data); // Remove the title from the description new_item.setData ("description", data.slice(data.indexOf("\r\n"))); // Remove the title and stats from the visible description new_item.setData("visibledesc", data.slice(data.indexOf("\r\n"), data.indexOf("From: "))); // // Fix for livejournal entries without titles // var test_data = new_item.getData ("matchtitle"); if (test_data.length) { new_item.setData ("visibletitle", test_data) } else { var first_line_re = new RegExp (".........*?[.:?\r\n]"); if (m = first_line_re.exec (data)) { data = m[0]; if (data[data.length-1] == '\r' || data[data.length-1] == '\n') { data = data.substring (0, data.length); } } data = data.substring (0, 80); if (data.length == 80) { if ((index = data.lastIndexOf (' ')) > 25) { data = data.substring (0, index); } data += "..."; } new_item.setData ("visibletitle", data) } // Fix for YouTube's brackets-around-links problem var checkLink = new_item.getData("link"); if(checkLink.indexOf('(') == 0) { // YouTube's links may be of the form ('http://.....',), so remove the first 2 and last 3 characters. checkLink = checkLink.slice(2, (checkLink.length - 3)); new_item.setData("link", checkLink); } } return true; } function myUpdate (existing_item, properties) { // Update using the new properties _t( "myUpdate()" ); myCreate(properties); return true; } function imageBlacklisted (url) { if (url.indexOf ("r.feedster.net") != -1) { return true; } return false; } // ---------------- Useful Trace Code ------------------- function show_state() { _t( "show_state()" ); dumpItems(); dumpItemsDeleted(); show_all_prefs(); queryListControl(); } function dumpItems() { if( Items.length == 0 ) { trace( "There are no items in the Items[] array\r\n" ); return; } for( i = 0; i < Items.length; i++ ) { trace( "Items[" + i + "]: \r\n" ); queryItem( Items[i] ); } } function dumpItemsDeleted() { if( Items.Deleted.length == 0 ) { trace( "There are no items in the Items.Deleted[] array\r\n" ); return; } for( i = 0; i < Items.Deleted.length; i++ ) { trace( "Items.Deleted[" + i + "]: \r\n" ); queryItem( Items.Deleted[i] ); } } function queryItem( item ) { trace( "----\r\n" ); trace( " item.text = \"" + item.text + "\" (string)\r\n" ); trace( " item.url = \"" + item.url + "\" (string)\r\n" ); trace( " item.note = \"" + item.note + "\" (string)\r\n" ); trace( " item.extra = \"" + item.extra + "\" (string)\r\n" ); trace( " item.hidden = " + item.hidden + " (boolean)\r\n" ); trace( " item.visited = " + item.visited + " (boolean)\r\n" ); trace( " item.canpurge = " + item.canpurge + " (boolean)\r\n" ); trace( " item.alerting = " + item.alerting + " (boolean)\r\n" ); trace( " item.creation = " + item.creation + " (double)\r\n" ); trace( " item.pubdate = " + item.pubdate + " (double)\r\n" ); trace( " item.lastmodified = " + item.lastmodified + " (double)\r\n" ); trace(" -- \r\n" ); trace( " item.tagged = " + item.tagged + " (text)\r\n" ); trace( "\r\n" ); } function queryListControl() { for (var lc_index = 0; lc_index < lcSource.length; lc_index++) { var index = lcSource[lc_index].offset + i; for (var i = 0; i < lcSource[lc_index].length; i++ ) { _t( "lcSource: " + lcSource[lc_index].getState( i ) + " multiFeeds: " + multiFeeds[i + lcSource[lc_index].offset].updated + " - name: " + multiFeeds[i + lcSource[lc_index].offset][NAME] ); } } } function show_all_prefs() { var i; trace( "------------------------\r\n" ); for (i = 0; i < Prefs.length; i++) { trace("Prefs["+i+"]: '"+Prefs[i].name+"' == '"+Prefs[i].value+"'\r\n"); } trace( "------------------------\r\n" ); } // // Trace code // var gTrace = false; // Turn on trace code function _t( s ) { if ( gTrace ) { trace( Prefs.title + ": " + s + "\r\n" ); } } ]]>