How to Use the FlickrNet API to Merge Flickr Accounts
A few months ago, my wife finally convinced me that it doesn't make any sense to manage two separate pro Flickr accounts, and that we should transfer all the photos to one account and drop the other.
So, I looked online for tools that merge Flickr accounts, and couldn't find any. Not even on
CodePlex. Don't get me wrong, I found a gazzillion mass downloaders, and uploaders and a bunch of other very cool
stuff. But not a merge tool. I even contacted Flickr support, but they were totally useless.
What I really wanted was a way to download the photos from the source account, and keep all the metadata I have meticulously added to the photos over the years - titles, descriptions, sets, tags, geo tags, etc. Then, upload to the target account without disrupting the flow on my
photostream. I didn't want a bunch of old photos clogging it up.
Being a developer, I decided to write my own Flickr app using the
FlickrNet API library, which turned out to be fun and quite enjoyable.
I don't want to bore you with all the details of my implementation. I'd just like to point out some interesting aspects and potential pitfalls.
Getting an API Key
To get started, you'll need an API key from Flickr. Go to the
Services page and click on the "Apply for an API Key" link.
The FlickrNet Library
Download the
FlickrNet library from CodePlex. You can download the binaries and reference the DLL from your code. I opted for the more geeky option, and downloaded the source code, and added the FlickrNet project to my solution. This way I could step through the code and better understand how it works.
Authorizing
If you want your app to do more than merely download public photos, your users will need to authorize it. The process is quite simple, but not that obvious. You need to launch a web browser and navigate to a Url. Here's what you do to get the Url.
FlickrNet.Flickr flickr = new FlickrNet.Flickr(ApiKey, SharedSecret);
string frob = flickr.AuthGetFrob();
string url = flickr.AuthCalcUrl(frob, FlickrNet.AuthLevel.Write);
AuthLevel can be one of the following values:
Once you have the Url, launch the default web browser.
System.Diagnostics.Process.Start(url);
At this point, the user needs to login to her account and authorize the application. Now you can retrieve the authorization token from Flickr.
FlickrNet.Flickr flickr = new FlickrNet.Flickr(ApiKey, SharedSecret);
FlickrNet.Auth auth = flickr.AuthGetToken(frob);
string token = auth.Token;
string userName = auth.User.Username;
Downloading Photos Metadata
This is a relatively simple process. Use the PhotoSearchOptions object to define the photos you are interested in (this could be based on a user, tag, etc.). The PhotosSearch method doesn't return all the photos it finds in one call, rather it returns "pages" of photos. You use the same PhotoSearchOptions to move to the next page and bring the next batch of results.
// Get the user Id based on the user name
FlickrNet.Flickr flickr = new FlickrNet.Flickr(ApiKey, SharedSecret);
FlickrNet.FoundUser user = flickr.PeopleFindByUsername(UserName);
string userId = user.UserId;
// Create a PhotoSearchOptions object
FlickrNet.PhotoSearchOptions options = new FlickrNet.PhotoSearchOptions();
options.UserId = userId;
// Retrieve the user's photos
FlickrNet.Photos photos = flickr.PhotosSearch(options);
Downloading Sets Metadata
// Get all the photosets for the user
FlickrNet.Photosets sets = flickr.PhotosetsGetList(userId);
Linking Photos to Photosets
This is where it gets a little tricky. See, Flickr allows photos to belong to 0-n sets. So, in theory I had to account for photos that are not part of any set, photos that belong to a single set, and for photos that belong to multiple sets. Since almost all of my photos belong to just one set, I've decided to cut myself some slack, and only deal with 0-1 sets per photo.
foreach (FlickrNet.Photoset set in sets.PhotosetCollection)
{
...
... //Save photoset metadata
...
// Get the photoset's photos
FlickrNet.Photoset set1 = flickr.PhotosetsGetPhotos(set.PhotosetId);
FlickrNet.Photo[] setPhotos = set1.PhotoCollection;
foreach (FlickrNet.Photo photo in setPhotos)
{
...
... // Link photo to photoset
...
}
}
Downloading Photos
The one thing to keep in mind here is that Flickr stores multiple versions of each photo (with different resolutions), so you want to make sure you download the largest one.
FlickrNet.Sizes sizes = flickr.PhotosGetSizes(photo.PhotoId);
FlickrNet.Size size = sizes.SizeCollection[sizes.SizeCollection.Length - 1];
string sourceUrl = size.Source;
string fileName = size.Source.Substring(size.Source.LastIndexOf("/") + 1);
WebClient client = new WebClient();
client.DownloadFile(sourceUrl, fileName);
Uploading Photos
Uploading the photos is easy. I just had to change the dates on the photo after the upload to make sure it shows up in the correct place in my photostream based on the upload date, and add the GEO tags, if they existed in the original metadata.
FlickrNet.Flickr flickr = new FlickrNet.Flickr(ApiKey, SharedSecret, AuthToken);
string photoId = flickr.UploadPicture(fileName, title, description, tags, true, false, false);
flickr.PhotosSetDates(photoId, datePosted, dateTaken, FlickrNet.DateGranularity.FullDate);
flickr.PhotosGeoSetLocation(photoId, latitude, longitude);
Creating Photosets
Creating a Photoset is a breeze. Just remember to assign a primary photo to the set, and make sure the photo id is the new photo id (from the target account) not the old one.
FlickrNet.Flickr flickr = new FlickrNet.Flickr(ApiKey, SharedSecret, AuthToken);
FlickrNet.Photoset set = flickr.PhotosetsCreate(title, description, primaryPhotoId);
Now you can add the photos (already uploaded) to the newly created set.
flickr.PhotosetsAddPhoto(photosetId, photoId);
Conclusion
Working with the FlickrNet API is both easy and fun. I'm personally happy I've decided to write my own app, I think I've learned a lot from it. If you are like me, and believe that
reading code makes you a better developer, I recommend downloading the source code version and using is in your solution.
Related Links
Coding4FunFlickr ExplorerFlickr API
Read more...