pyShortUrl – A url shortening lib in python

pyShortUrl - A url shortening lib in python

pyShortUrl - A url shortening lib in python

Its been sometime since I got on to twitter. And every time I happen to tweet a link, I watch my incredibly long urls magically shrink to a few chars. A few days ago, I happened to do a quick google search on url shortening that revealed some interesting info and I soon found myself playing with it. Here’s what came out of it.

URL shorteners are used to transform huge, ugly looking, difficult to remember (and manage) urls into short urls. For instance take this url: http://maps.google.com/maps?q=-27.103602,-109.290791&hl=en&sll=-27.103602,-109.290791&sspn=0.097646,0.181446&t=h&z=13. When shortened using goo.gl, this turns into http://goo.gl/FDlHE. Any HTTP request to this short url gets redirected to the original url. It goes without saying that such small urls are extremely easy to handle.

It is very common to want to share a link on the internet today. Oftentimes, the link we want to share is on the domain that is not controlled by us. This makes it difficult to track the number of visits to the url you shared. In this case, you can create a short url for the original url, share the short url and let the url shortening service maintain the statistics for you. This is just one of the scenarios where url shortening comes handy. While url shortening does have other uses, it is absolutely necessary (read: inevitable) for micro-blogging sites like twitter which impose strict constraints over the max number of characters that may be used in a post.

If you are an application developer trying to build url shortening capability into your application, you will need to pick a url shortening service (trust me, there are more than you might imagine) and implement the APIs provided by that service. Alternatively, you could use pyShortUrl.

pyShortUrl is a library, I wrote recently in python, that you can use from within your application to shorten your urls. I added initial support for 7 domains: goo.gl, bit.ly, j.mp, bitly.com, tinyurl.com, v.gd & is.gd. pyShortUrl will also allow you to get QR code for short urls created using most of these services.

Following is an example of how urls can be shortened with pyshorturl using goo.gl:


from pyshorturl import Googl, ShortenerServiceError

long_url = 'http://www.parthbhatt.com/blog/2012/'
service = Googl()
try:
    short_url = service.shorten_url(long_url)
    print short_url
except ShortenerServiceError, e:
    print 'Error: %s' %e

If you want to keep track of urls you shortened and are interested in statistics showing things like how many times your shortened url was accessed, you can specify an API key while creating the Googl object. pyShortUrl offers similar functionality with other supported url shortening services as well. For details about how to use pyShortUrl with other url shortening services, checkout the README file for the project on github.

Depending upon the service you choose, you may be required to create an account with the service. Also, note that you will have to abide by the rate limiting constraints imposed by the url shortening service you choose. For all such details about various services supported by pyShortUrl, checkout this wiki page.

Also, don’t forget to checkout the pyshorturl-cli.py utility that is shipped with the library. It is a command line utility that offers all the functionality of pyShortUrl. Following is a quick example of how you’d use pyshorturl-cli.py to shorten a url with bit.ly:


$ python pyshorturl-cli.py --service bit.ly \
      --api-key <bitly-api-key> --login <bitly-account> \
      --long-url http://www.parthbhatt.com/blog/2012/

http://bit.ly/IlLRrd

To find out how to get your <bitly-api-key> and <bitly-account> refer to this wiki page.

shutterflow: Photography workflow, made easy.

Shutterflow

So, it started with the thought of publishing some of the photos, I managed to click, online. The task would involve going thru the usual process of: Copy photos form my camera to my computer. Then watermark them. Then, possibly, add a frame around the image and finally publish to my favorite photo sharing service.


Since, I have been uploading some of my photos to flickr already, I needed a good way to batch edit my photos and push them to flickr. I looked around and found quite a few tools. Generally, the reason I did not end up using one of the available tools was either they were expensive or they did not seem to fit my exact requirements. So I thought I would try my hand at writing one of my own.

Initially, FWIW, the idea of going the gimp plugin way did seem interesting. Another idea was to build an app around ImageMagick. Given that gimp and ImageMagick are both fantastic at what they do, either of these ideas would have taken away the burden of implementing anything that had to do with image editing.

However, what I was looking to create was kind of a photography workflow solution. Not quite an image editing application. As far as image editing goes, I would be fine with having a minimal set of filters, that may not be very hard to implement. What was more important was to have a feature set suited for photographers.

And hence I kicked off shutterflow !! The idea behind shutterflow is to build a tool from ground up that was targeted to make the tasks, a photographer performs on a regular basis, extremely easy. Shutterflow would contain a minimal set of image filters/transforms. It would allow you to save all filters/transforms that you apply to your images, so that you can re-apply them again to a different image. Moreover, it will let you define, what one would call, a workflow. A workflow would be set of tasks that will be performed in sequence on an image. A task inside a workflow could be to apply a watermark or brighten an image or crop an image based upon specified constraints, or even upload to flickr (or facebook or picasaweb/Google Photos for that matter). To batch edit photos, this workflow can then be applied to, say, a directory of images.

Of course, it’ll be a while before shutterflow becomes capable of doing all of this. As of today it can barely watermark images and upload to flickr. Batch editing still needs to be brought in. And so does support for more photo sharing services. I haven’t even started to think about raw image formats, etc.

So what is shutterflow built using? Java Advanced Imaging (JAI) seemed pretty cool. Plus, I knew a little bit of Java Swing. So it wasn’t hard to zero in upon Java. Project hosting on sourceforge.net, git for SCM and apache ant for the build system.

Hopefully, in a matter of time, shutterflow will help scratch my itch as well as that of a few others ! Meanwhile, checkout the shutterflow website and keep watching the download section.

Geolocation with Google Maps JavaScript API

In the previous post, we saw how W3C Geolocation API can be used to obtain a user’s location. In this post we will see how the obtained geolocation information can be displayed on a map, using Google Maps JavaScript API v3. We will also see how location information in terms of (latitude, longitude) can be translated into a readable (street) address. This process of obtaining street address from a point location is called Reverse Geocoding.

Google Maps JavaScript API is a JavaScript library that lets you build maps based applications for the web (desktop based browsers and mobile devices).

Note that the intent of this post is not to show how to use the Google Maps JavaScript API. Instead, it is to show how to display the position obtained using the W3C Geolocation API, on a map. For a tutorial on Google Maps JavaScript API, check this out.

First of all, lets see how a map can be displayed on a web page using the Google Maps JavaScript API.


<HTML>
  <HEAD>
    <TITLE>Google Maps JavaScript API Example</TITLE>

    <LINK href="http://code.google.com/apis/maps/documentation/javascript/examples/default.css" rel="stylesheet" type="text/css" />
    <!-- Load the Google Maps JavaScript API v3 -->
    <SCRIPT type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></SCRIPT>

    <SCRIPT type="text/javascript">
      var bangalore = new google.maps.LatLng(12.940322,77.607422);
      var map;

      function initMap()
      {
        var map_options = {
          zoom: 10,
          mapTypeId: google.maps.MapTypeId.ROADMAP
        };
        map = new google.maps.Map(document.getElementById("map_canvas"),
            map_options);

        map.setCenter(bangalore);
        display_text = "<P>Bangalore,<BR/>Karnataka, India</P>" + bangalore;
        showInfoWindow(display_text);
      }

      function showInfoWindow(info_message)
      {
        info_window = new google.maps.InfoWindow();
        info_window.setContent(info_message);
        info_window.setPosition(bangalore);
        info_window.open(map);
      }
    </SCRIPT>
  </HEAD>
  <BODY onload="initMap()">
    <DIV id="map_canvas"> </DIV>
  </BODY>
</HTML>

Following is an extension of the script in the previous post. Besides obtaining the user’s location, it displays the same on a map. It also shows the street address by reverse geocoding on the location returned by W3C Geolocation API.


<HTML>
  <HEAD>
    <TITLE> W3C Geolocation API + Google Maps JavaScript API</TITLE>

    <LINK href="http://code.google.com/apis/maps/documentation/javascript/examples/default.css" rel="stylesheet" type="text/css" />
    <!-- Load the Google Maps JavaScript API v3 -->
    <SCRIPT type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></SCRIPT>

    <SCRIPT type="text/javascript">
      var bangalore = new google.maps.LatLng(12.940322,77.607422);
      var info_window = new google.maps.InfoWindow();
      var initial_location;
      var geo_position;
      var map;

      function getGeolocation()
      {
        var map_options = {
          zoom: 14,
          mapTypeId: google.maps.MapTypeId.ROADMAP
        };
        map = new google.maps.Map(document.getElementById("map_canvas"),
            map_options);

        // Check if the client browser supports W3C Geolocation APIs.
        if(navigator.geolocation)
          navigator.geolocation.getCurrentPosition(handleGeolocationData,
                                                   handleGeolocationError);
        else
          handleGeolocationError(null);
      }

      function handleGeolocationData(position)
      {
        initial_location = new google.maps.LatLng(position.coords.latitude,
            position.coords.longitude);
        map.setCenter(initial_location);
        geo_position = position;
        reverseGeocode();
      }

      function reverseGeocode()
      {
        rev_geocode_req = {'latLng': initial_location};
        geocoder = new google.maps.Geocoder();
        geocoder.geocode(rev_geocode_req, showResults);
      }

      function getResultDescription(result)
      {
        timestamp = new Date(geo_position.timestamp);
        info_text = result.formatted_address + '<BR/>';
        info_text += result.geometry.location.toString() + '<BR/>';
        info_text += 'Accuracy: ' + geo_position.coords.accuracy + ' meters <BR/>';
        info_text += 'Timestamp: ' + timestamp + '<BR/>';

        return info_text;
      }

      function showResults(results, status)
      {
        result_html = "Failed to obtain your street address.";

        if (results)
        {
          if (status == google.maps.GeocoderStatus.OK)
          {
            /*
            for (var i = 0; i < results.length; i++)
              result_html += getResultDescription(results[i]);
            */
            result_html = getResultDescription(results[0]);
          }
        }
        showInfoWindow(result_html);
      }

      function handleGeolocationError(position_error)
      {
        error_info = "W3C Geolocation Unavailable. <BR/>";
        if (null == position_error)
          error_info += "Geolocation API not supported by your browser.";
        else if (position_error.PERMISSION_DENIED == position_error.code)
          error_info += "PERMISSION_DENIED: Your client is not permitted to share your location.";
        else if (position_error.POSITION_UNAVAILABLE == position_error.code)
          error_info += "POSITION_UNAVAILABLE: Unable to find your location.";
        else if (position_error.TIMEOUT == position_error.code)
          error_info += "TIMEOUT: Timeout while finding your location.";
        else
          error_info += "Unknown error occured while finding your location.";
        error_info += '<BR/>';
        error_info += 'Placing you in Bangalore.';

        initial_location = bangalore;
        map.setCenter(initial_location);
        map.setZoom(10);
        showInfoWindow(error_info);
      }

      function showInfoWindow(info_message)
      {
        info_window.setContent(info_message);
        info_window.setPosition(initial_location);
        info_window.open(map);
      }
    </SCRIPT>
  </HEAD>
  <BODY onload="getGeolocation()">
    <DIV id="map_canvas"> </DIV>
  </BODY>
</HTML>

Click here to see this code in action.

W3C Geolocation API

Published by in Maps on June 22nd, 2011

I’ve always liked the idea of a service that provides information keeping in mind the location from which it is requested. That certainly is a way to fill the user with information that is most relevant. For example, consider an application that shows all Chinese restaurants around you as opposed to an app that just shows you all Chinese restaurants. Or may be an app that says how far you are from the nearest KFC! Or a photo sharing site that can show you photos taken around you (yes, I am talking about Flickr).

But, how would these services work? How could such a service identify where the user is located? If the idea of finding answers to these questions fascinates you, read on!

Short answer to these questions is W3C Geolocation APIs.

W3C geolocation API helps you build applications that are location-aware, by providing a standardized way of programmatically obtaining a user’s location information from a client-side application. This information can be shared with trusted web sites, so that these websites can provide services keeping in mind where the user is located. So that you, as a user, are furnished with information that is most relevant to you.

To obtain the user’s location, the client (browser) contacts a location information server (e.g. Google Location Services) and the user’s location is determined on the basis of information like visible access points (their location and signal strength), your IP address, getting your location from a GPS device, GSM/CSMA cell ids, Bluetooth MAC address, RFID etc.

Note that the geolocation APIs, however, are totally agnostic to the way the client obtains the user’s location. Therefore, an application that makes use of the geolocation API, does not have to worry about the intricacies of how the user’s location would be obtained. In other words, the underlying client implementation (possibly, a web browser) takes care of actually figuring out the user’s physical location and providing it to the consumer of the APIs (the client side script using the geolocation APIs).

The W3C Geolocation API spec can be found here. The rest of this article focuses on how these APIs can be used.

The code snippet below uses the geolocation APIs to identify the user’s location:

<HTML>
  <HEAD>
    <TITLE>W3C Geolocation Example</TITLE>
    <SCRIPT type="text/javascript">
    function getGeolocation()
    {
      // Check if the client browser supports W3C geocoding.
      if(navigator.geolocation)
        navigator.geolocation.getCurrentPosition(handleGeolocationData,
                                                 handleGeolocationError);
    }

    /* Success callback for navigator.geolocation.getCurrentPosition()
     */
    function handleGeolocationData(position)
    {
      latitude = position.coords.latitude;
      longitude = position.coords.longitude;

      alert ("Your location: (" + latitude + ", " + longitude + ")");
    }

    /* Failure callback for navigator.geolocation.getCurrentPosition()
     */
    function handleGeolocationError(position_error)
    {
      alert ("Unable to find your location.");
    }
    </SCRIPT>
  </HEAD>
  <BODY onload="getGeolocation()">
  </BODY>
</HTML>

Click here to see this code snippet in action. Note that, as you already know, this page will determine your location, which is not saved anywhere on this site.

Of course, this script needs better error handling. Specifically, when geolocation fails, it can’t identify why it failed. But we’ll look into that bit in a while. For now lets focus on what it does rather than what it does not do.

If you save this in an html page and open it in your web browser, you should see a prompt asking you if you wish to share your location information (unless your browser does not support W3C geolocation API). The prompt will look something like this:

Unless you click on “Share Location”, you will not see your location.

Lines 9-10 in the snippet above use getCurrentLocation(), which is an asynchronous API. We pass two callback functions to getCurrentLocation(). The first, handleGeolocationData(), would get called if geolocation data is available and the other, handleGeolocationError(), would get called in case when geolocation data is not available. The call to getCurrentLocation() returns immediately and then one of the callback functions is called depending upon the fate of the browser’s attempt to identify the user’s location.

As you might have noticed, the success callback is called with a parameter. This parameter is an object of type Position. It contains all the available info about the user’s location.

The failure callback is called with an object of type PositionError. This helps the failure callback function to identify what went wrong.

Lets improve this script a bit and try to make it a little more robust.

<HTML>
  <HEAD>
    <TITLE>W3C Geolocation Example</TITLE>
    <SCRIPT type="text/javascript">
    function getGeolocation()
    {
      // Check if the client browser supports W3C Geolocation APIs.
      if(navigator.geolocation)
        navigator.geolocation.getCurrentPosition(handleGeolocationData,
                                                 handleGeolocationError);
      else
        handleGeolocationError(null);
    }

    function handleGeolocationData(position)
    {
      // The timestamp is in a DOMTimeStamp object, which is milliseconds
      // since the start of the Unix Epoch. So we need to convert it.
      timestamp = new Date(position.timestamp);

      location_info = "Your Geolocation Information: <BR/><BR/>";
      location_info += "Timestamp: " + timestamp.toLocaleString() + "<BR/>";
      location_info += "Latitude and Longitude: (" + position.coords.latitude + ", " + position.coords.longitude + ") <BR/>";
      location_info += "Accuracy: " + position.coords.accuracy + " meters<BR/>";

      // Check if any of the optional attributes of position.coords is specified.
      if (position.coords.altitude)
        location_info += "Altitude: " + position.coords.altitude + "<BR/>";
      if (position.coords.altitudeAccuracy)
        location_info += "Altitude Accuracy: " + position.coords.altitudeAccuracy + "<BR/>";
      if (position.coords.heading)
        location_info += "Heading: " + position.coords.heading + "<BR/>";
      if (position.coords.speed)
        location_info += "Speed: " + position.coords.speed + "<BR/>";

      document.getElementById("location").innerHTML = location_info;
    }

    function handleGeolocationError(position_error)
    {
      error_info = "W3C Geolocation Unavailable. <BR/>";
      if (null == position_error)
        error_info += "Geolocation API not supported by your browser.";
      else if (position_error.PERMISSION_DENIED == position_error.code)
        error_info += "PERMISSION_DENIED: Your client is not permitted to share your location";
      else if (position_error.POSITION_UNAVAILABLE == position_error.code)
        error_info += "POSITION_UNAVAILABLE: Unable to find your location.";
      else if (position_error.TIMEOUT == position_error.code)
        error_info += "TIMEOUT: Timeout while finding your location.";
      else
        error_info += "Unknown error occured while finding your location.";

      document.getElementById("location").innerHTML = error_info;
    }
    </SCRIPT>
  </HEAD>
  <BODY onload="getGeolocation()">
    <DIV id="location"> </DIV>
  </BODY>
</HTML>

The code above displays all the location information that is made available to the success callback function. It also does a better job at error handling, identifying why geolocation failed.

To see how this example works, click here.

While, getCurrentPosition() helps get the location of the user in a one-shot manner, the geolocation API offers another function, watchPosition() that lets the application to monitor the position of a user. watchPosition(), once invoked, calls the success callback function every time a user’s location changes. Following is a snippet that shows use of watchPosition():

<HTML>
  <HEAD>
    <TITLE>W3C Geolocation Example</TITLE>
    <SCRIPT type="text/javascript">
      var watch_id;

      function initGeolocation()
      {
        // Check if the client browser supports W3C Geolocation APIs.
        if(navigator.geolocation)
          watch_id = navigator.geolocation.watchPosition(handleGeolocationData,
                                                         handleGeolocationError);
        else
          handleGeolocationError(null);
      }

      function unInitGeolocation()
      {
        // Clear the watch if we initialized it.
        if(navigator.geolocation)
          navigator.geolocation.clearWatch(watch_id);
      }

      /* The callbacks handleGeolocationData() and
       * handleGeolocationError() remain the same
       * and need to be added here. */
    </SCRIPT>
  </HEAD>
  <BODY onload="initGeolocation()" onunload="unInitGeolocation()">
    <DIV id="location"> </DIV>
  </BODY>
</HTML>

To checkout how this works, click here.

Both getCurrentPosition() and watchPosition() accept an optional third argument in the form of PositionOptions. This lets the caller control the behavior of the functions in terms of desired accuracy, if the caller is willing to accept cached location info and maximum time between the call to getCurrentPosition() (or watchPosition()) and the time at which one of the call backs are called.

It wouldn’t be entirely surprising if you have privacy concerns around sharing your physical location with a website out on the Internet. The W3C geolocation API addresses privacy concerns by mandating that a user agent must not send location information to web sites without user’s explicit consent, so that you are always in control with respect to who your location information is shared with.

While using the W3C geolocation APIs to obtain your location is quite interesting, that alone wouldn’t let you do much. Real fun starts when you club it with something like, say, Google Maps JavaScript API. That’s something we’ll probably talk about some other time!

© 2013 Parth Bhatt.