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" );
}
}
]]>