Home
z_default
I haven't really seen this spelled out in a really clear manner on the web, so let me help out. YouTube's got useful programmatic feeds. You can specify a feed for a user's videos like:

http://gdata.youtube.com/feeds/base/users/communitychannel/uploads

You can also specify the order in which you want the videos.  Note the "orderedby" parameter in the urls that follow:

http://gdata.youtube.com/feeds/base/users/communitychannel/uploads?orderby=updated
http://gdata.youtube.com/feeds/base/users/communitychannel/uploads?orderby=published

So far, so great. Now, suppose you want to make a lifestream, and you want to include the videos that you've favorited. They've got a feed for that, too:

http://gdata.youtube.com/feeds/api/users/davidblume/favorites

But it's not right.  If you look at the data you get back, you see that it's not what you wanted. Those videos are going to be associated with the timestamp with which they were updated or published, not the time that you favorited them. And that's the time that matters to your lifestream! Given the way the programmatic feeds are organized, you'd think that there's a way to specify that, and that feed would be as follows, right? --

http://gdata.youtube.com/feeds/api/users/davidblume/favorites?orderby=favorited

Nope. After living with a workaround in my lifestream for months, only today do I learn that YouTube did create the feed I needed, but calls it this: v=2. Yeah, like that jibes with their feed explanation.

Lifestream writers, the favorites feed (ordered by time favorited) that you want is constructed like this:

http://gdata.youtube.com/feeds/api/users/username/favorites?v=2

(Replace "username" with your username, of course.)  Now I can go delete my workaround.

z_default
Yeah, I know that that subject text is hard to read. Blame it on the insomnia. I like the LiveJournal them "Expressive" by Jared MacPherson, but one thing that bugs me about it is that list items at the top of the post tend to overlap with the userpic.

Here's an example:


Yuck. A fix for it is the following Custom Stylesheet code:

.asset-body ol { list-style: decimal inside; }
.asset-body ul { list-style: disc inside; }

If you customize Expressive with the CSS above, then your journal won't have list bullets that overlap the user icon.  Here's a link to the corrected page in the picture above.

Tags:

User feeds should reflect user activity

  • Oct. 12th, 2008 at 8:12 PM
z_default

RSS and Atom feeds are a lot of fun! The most common use of these feeds is to subscribe to them in a feed reader so that you can browse through individual articles from multiple sources in chronological order.

Another fun thing to do with them is to create a lifestream. That's a collection of feeds associated with a person. The first one that caught my attention was Jeremy Keith's. Mine is stylized identically to his, but the back-end is different, and the functionality is different. I'll cover that in a different post.

Creating my lifestream put me in a position to discover which tech companies provide the most and least useful services. For example, I think it's awesome that Hulu provides a feed for which videos I watch.  It's also awesome that Netflix offers different feeds (sent/enqueued/etc.) for their users' queues.

Here are the three companies that I thought would get it, but really ended up frustrating me:
  • Amazon does not provide an Atom or RSS feed for its users' wishlists.
  • Shelfari (owned by Amazon) does not provide a feed for its users' shelves.
  • YouTube does not provide a user-oriented feed for its users' favorited videos.
This, folks, is madness.

Their users want to draw attention to the best of the products these companies promote and offer. But Amazon, Shelfari and YouTube don't provide the mechanism. That's a bit like saying, "we don't want more eyeballs on our products."



Ideally, you could have a feed of the items you added to your Amazon wishlist, sorted chronologically by the date you added the item to your wishlist. Amazon doesn't provide that. That's really frustrating, because if you go to your wishlist page, it says, "added [date]" right there, next to each item.

At best, they provide a list that can be widgetized into a blog sidebar.  That's good, but a widget doesn't serve the same purpose as a feed.  With the help of Yahoo Pipes, you can come close enough to the feed we really want. Here's the URL you need:
http://webservices.amazon.com/onca/xml?Version=2006-06-07&Sort=DateAdded&
     Service=AWSECommerceService&ResponseGroup=ListFull&Operation=ListLookup&
     ListType=WishList&ListId=[id]&AssociateTag=[assoc]&AWSAccessKeyId=[key]
Extract item.Item.ItemAttributes.Title and item.DateAdded from each item, and insert them into a custom feed accordingly. Voila, the feed that Amazon should be providing itself.



Shelfari suffers from the same problem as with Amazon. You can get a widget. But you can't get a feed that says when you added the book to your shelf, or when you started reading it, or when you finished and reviewed the book. Users have been asking Shelfari for that for nine months.

I don't have a workaround for this one. It's better to just use a services that provides the right feeds, like librarything.com or goodreads.com.



YouTube has awesome feed support. That keyword support is brilliant. So it breaks my heart to say that they really missed the boat when it comes to favorited videos. YouTube does support a feed of video that have been favorited by a user.

http://gdata.youtube.com/feeds/api/users/[user]/favorites

But the videos aren't sorted by when they were favorited. That's really frustrating, because when you go to your profile page, it says right there, when each video was favorited.

The profile page presents the info, but the favorites feed doesn't.  Instead, they're sorted by when the videos were most recently commented upon.

If we're going to subscibe to a user's list of favorited videos, it's pretty safe to assume that we're interested in when that user favorited those videos.  If they favorited something recently, we want it at the top of that feed.  Simple.

My only workaround for the current feed involves parsing their feed, and comparing each item against a previously gathered list of known favorites.  If there are any new favorites, add them with the current timestamp.

[Edit] Youtube eventually made the feed we need.

Summary

We, as users, shouldn't have to be coding around the services that these companies offer.  The companies should recognize the obvious value inherent in useful user feeds that point to their most popular products.

C'mon, Amazon, Shelfari, and YouTube.  Give us our feeds.

Lifestream Status

  • Aug. 28th, 2008 at 8:00 PM
z_default
My current programming project is a custom made lifestream. It's fun!

Think there's privacy online? Here are a few of the public feeds that track me.  Since they're there already, I'm going to aggregate them into one place.  It'll be like a digital diary that writes itself.
 

Edit: Ha, ha.  I forgot my livejournal.

Tags:

z_default
The RSS specification allows you to have an <image> element in the header of your RSS feed.  A long time ago, if you used Wordpress, you'd have to edit the wp-rss.php file and be very careful when you upgraded to new releases, or your change could be lost.

But if you use a modern version of Wordpress, you should take advantage of the do_action('commentsrss2_head') hooks* in the feed-rss... .php files.

Here's what you'd do: Add the following code to your theme's functions.php file:

function add_my_rss_image()
{
echo '<image><title>', bloginfo_rss('name'), '</title>';
echo '<url>', bloginfo_rss('stylesheet_directory'), '/images/button.gif</url>';
echo '<link>', bloginfo_rss('url'), '</link>';
echo '<width>88</width><height>31</height>';
echo '<description>Description of your blog.</description></image>';
}

add_action('rss2_head','add_my_rss_image');
add_action('rss_head','add_my_rss_image');
add_action('commentsrss2_head','add_my_rss_image');

Take care to actually put an image file in the path specified, and adjust the width and height accordingly.

Et, voila! Now your feeds have images, and they're forwards compatible with future versions of Wordpress. Oh, did I say future versions of Wordpress? Excuse me, I have to:

svn sw http://svn.automattic.com/wordpress/tags/2.6/

Blam! Upgraded. Sweet.

* Also rss2_head and rss_head, just so I cover the appropriate Google terms.

Twitter friends again!

  • Jul. 15th, 2008 at 5:30 PM
z_default
Remember how angry I was at twitter? They turned off open friends feeds subscription since the WWDC?

It turns out the solution I needed was a one-liner cron job.

curl -u email:password http://twitter.com/statuses/friends_timeline.rss > twitter_friends.rss

::slaps head::

Now I can use Google Reader again.  Thanks, Twitter API.  We can be friends again.

Tags:

The Unofficial Plurk API in Python

  • Jul. 14th, 2008 at 1:52 PM
technical
I've ported some of the unofficial Plurk API in Python at Google Code.

There were already a couple Python scripts out there that connect to Plurk, but nothing that constituted anything like an API like Ryan Lim's PHP version.

It's only a partial port, and it's not documented yet. But it's pretty easy to understand and it's usable. If you use it, please conform to Plurk's Terms and Conditions.

Here are some examples:
import plurkapi

p = plurkapi.PlurkAPI()

## View some plurks
for plurk in p.getPlurks(your_userid):
print plurk['content']

## Retrieving Karma
p.login(nickname, password)
print "%s has %1.2f karma." % (p.nickname, p.uidToUserinfo(p.uid)['karma'])

Rockin' The Geek-Fu, or Not On Your Cloud

  • Apr. 19th, 2008 at 12:12 AM
technical
I use Foxmarks to keep different computers' bookmarks sync'ed to each other. I have one set of bookmarks for use on home computers, and another set for use at work computers. (I also use delicious for low usage bookmarks I know I want available everywhere.)

With Foxmarks, you can sync your bookmarks to their servers, or you can sync to your own webdav server. I prefer to host my own stuff, so I sync to my own webdav server. The bookmarks are stored in JavaScript's json file format.

But, that doesn't give me the option to browse to the server and easily see the other set of bookmarks. (If I sync'ed to Foxmarks' servers, then I could see them at my.foxmarks.com if I login with my other username.)

What's a Pythonista to do? Write a script that displays the bookmarks as URLs on a webpage! Sweet! Now I host my own repository for my bookmarks, and they're available online in case I need to see the other set's bookmarks. Here's the script:

#!/usr/bin/python
# foxmarks_reader.py by David Blume

import urllib
import simplejson # http://www.undefined.org/python/
import types

urls = ( ('Home Computer', r'http://user:pwd@url.com/fm/foxmarks.json'),
         ('Work Computer', r'http://user:pwd@url.com/fmw/foxmarks.json')
         )

def do_insert(folders, command):
    if 'nid' in command:
        args = command['args']
        if args.has_key('ntype'):
            if args['ntype'] == 'folder':
                my_folder = []
                folders[command['nid']] = my_folder
                if command['nid'] != 'ROOT':
                    parent = folders[args['pnid']]
                    parent.append((args['name'], my_folder))
            elif args['ntype'] == 'separator':
                parent = folders[args['pnid']]
                parent.append('---')
            else: # 'bookmark'
                parent = folders[args['pnid']]
                parent.append('<a href="%s">%s</a>' % (args['url'], args['name']))

def print_folders(folders, indent):
    for item in folders:
        if type(item) == types.ListType or type(item) == types.TupleType:
            print '%s%s' % ('  '*(indent * 4), item[0].encode('iso-8859-1', 'replace'))
            print_folders(item[1], indent + 1)
        else:
            print '%s%s' % ('  '*(indent * 4), item.encode('iso-8859-1', 'replace'))

if __name__=='__main__':
    print "Content-type: text/html; charset=ISO-8859-1\n\n"
    print '<pre>'
    for url in urls:
        print '<h2>%s</h2>' % url[0]
        sock = urllib.urlopen(url[1])
        json = simplejson.load(sock)
        sock.close()
        folders = {}
        for command in json[u'commands']:
            do_insert(folders, command)
        print_folders(folders['ROOT'], 0)
    print '</pre>'

Tags:

My Compromised Blog

  • Jan. 24th, 2008 at 4:43 PM
technical
I was doing some general cleanup around the blog. (Considering widgetizing the sidebar...) I re-validated the XHTML, and some errors came up. The following code was inserted into the content of a post. (Which is contained inside a MySQL item.)


<p id="displayer" style="display:none">
CD and DVD films available for download at <a href="http://my-movie-download.com/">download movies</a> site, cheap prices and fast downloading.</p>


The evil little snippet above says that humans won't be bothered with the link, but search engines will notice it.  Also, the following was actually inserted into my theme's index.php.


<form id="srch" name="srch" style="overflow:hidden;width:0pt;height:0pt" method="post">
DiVX and DVD films available at <a href="http://my-movie-download.com/">download movies</a> portal, low prices and fast downloading.
</form>


Just like the prior snippet, humans won't see the link, but search engines will.

It's hard to describe how annoying this is. Somebody/bot found a way to compromise my blog's directory and its database.  I only sftp and ssh to the site. (Although in the past I have ftp'ed. No more!) I thought I chmodded the wordpress files to -rw-r-----, but I see now that there are more extensive write permissions in some directories.

I checked the last few logins, but they were all mine this month.  (And my host clears the log every month.)  I have to monitor the situation closely.

Ye gods, the referrer spam goons are aggressive!  Aargh!
technical
How hard do I rock?  Let me give you an example.

Date:  The near future.

Scene: David's blog, a jewel of php code, with a few custom modifications to the WordPress framework.  Does anybody else have an <image> element in their <channel> in their feed-rss.php family?  Doubtful.  Oh, how about user friendly "there's more content this way" ellipses in their wp_trim_excerpt() function in their formatting.php?  Ha!  The world would be so much nicer if only they did.

But what's this?  There's danger brewing.

A vulnerability in the pingomatic server unleashes a feedback ping ripping a hole via XSS into every single wp_footer().  Everybody who posts, pings.  And everybody who pings gets spam added to their footer.  And everybody who pings suffers a debit from their PayPal account.

Never fear!  Matt Mullenweg's team of crack coders patches the hole the exploit accessed in the WordPress code.  But now WordPress users across the world must scramble to follow the tedious upgrade instructions.  And then re-apply their custom changes.

Oh, the humanity!  Why isn't David panicking?  Why isn't he in despair?  Doesn't he realize the danger to his blog?!  Doesn't he realize the tedium that awaits him?

Let's zoom in and see what he's doing...

David grabs a few dark chocolate covered espresso beans, and casually pops them into his mouth.  He ssh logs into his blog's directory.  He types,

svn sw http://svn.automattic.com/wordpress/tags/2.3.2/

and logs out.  He's done.  His blog is updated, protected, and his customizations are intact.  He turns up his MP3 player and goes outside to enjoy the sun.

(In other words: My blog is now a subversion sandbox.  Whee!)

Tags:

HP Printer Ready Message "INSERT COIN"

  • Oct. 17th, 2007 at 12:18 PM
technical
Courtesy of our local HP printers and this awesome tip, I present today's python script:
from socket import *
import sys

printer = "10.1.1.2"  # Change this to the IP of your printers
msg = "INSERT COIN"   # Or, AYBABTU for longer displays

if __name__=='__main__':
  if len(sys.argv) == 3:
    printer = sys.argv[1]
    msg = sys.argv[2]
  s = socket(AF_INET, SOCK_STREAM)
  send_message = \
    '\x1b%%-12345X@PJL JOB\n@PJL RDYMSG DISPLAY="%s"\n@PJL EOJ\n\x1b%%-12345X' % (msg, )
  s.connect((printer, 9100))
  s.send(send_message)
  s.close()

python arguments are post-its

  • Mar. 30th, 2007 at 8:39 PM
z_default
Consider:


>>> def foo(a): a = 2
...
>>> x = 1
>>> foo(x)
>>> x
1


And:


>>> def bar(b): b.append(2)
...
>>> y = []
>>> bar(y)
>>> y
[2]

Alex Martelli dismisses newbie "by value or by reference" questions with the following:

The terminology problem may be due to the fact that, in python, the
value of a name is a reference to an object. So, you always pass the
value (no implicity copying), and that value is always a reference.

I find it simpler to explain as: the semantics of argument passing are
_exactly_ identical to that of assignment (binding) to a barename; you
can fruitfully see argument passing as local (bare) names of the called
function being assigned initial values by the caller (that's exactly
what happens, in practice). Now if you want to coin a name for that,
such as "by object reference", "by uncopied value", or whatever, be my
guest. Trying to reuse terminology that is more generally applied to
languages where "variables are boxes" to a language where "variables are
post-it tags" is, IMHO, more likely to confuse than to help.