Currency Conversion with Javascript Iteration

Missing that handy currency/country conversion link on your favorite page? A quick bookmarklet can fix that.

We will put together some javascript to iterate over our currency elements to do the conversion for us. In this case, we are looking at the bicycle site road.cc and we wish to convert review prices from Pounds to US Dollars.

Screenshot 2013-12-29 22.55.21
road.cc reviews before conversion (http://road.cc/show/review-section/road-bikes/35)
Screenshot 2013-12-29 22.55.31
road.cc reviews after conversion (http://road.cc/show/review-section/road-bikes/35)

 

 

 

 

 

 

 

 

 

We first select all of our data of interest. In this case, our data is in a div with a specific class that merely contains the price.

var data = document.getElementsByClassName("review-price");

Next we will iterate over this data and convert the price using a decent approximation based upon today’s conversion rate. However, we have two considerations; the price div also contains the Pound character which we will first cut out before converting with the replace call and we will also want to round to two decimal places for sanity.

for (var i = 0; i < data.length; i++) {
   data[i].innerHTML = Math.round(data[i].innerText.replace('£', '') * 1.6479 * 100) / 100;
}

If you try and run this, you may notice one caveat – road.cc uses infinite scroll. This means that we will convert material that is currently loaded, however, upon scrolling down and with the loading of additional content, we would have to run the bookmarklet again to convert this newly loaded data. The problem is that we would convert our previously adjusted price data again. To prevent this issue, we can modify our code to convert data that begins with the Pound but not Dollar symbol.

function () {
    var data = document.getElementsByClassName("review-price");
    for (var i = 0; i < data.length; i++) {
        /* change class so we don't suck it up again since we have to re-run the bookmarklet
       again because of infinite scroll
      */
        if (data[i].innerHTML.indexOf("£") != -1) {
            data[i].innerHTML = '$' + Math.round(data[i].innerText.replace('£', '') * 1.6479 * 100) / 100;
        }
    }
}

Now, remember, we wrap this in a javascript declaration to create our bookmarklet. Thus, the final version will result in the following when we place our pieces of code together.

javascript: (

function () {
    var data = document.getElementsByClassName("review-price");
    for (var i = 0; i < data.length; i++) {
        /* change class so we don't suck it up again since we have to re-run the bookmarklet
       again because of infinite scroll
      */
        if (data[i].innerHTML.indexOf("£") != -1) {
            data[i].innerHTML = '$' + Math.round(data[i].innerText.replace('£', '') * 1.6479 * 100) / 100;
        }
    }
}())

Running the bookmarklet should now convert currency data to US Dollars which works with infinite scroll by re-clicking the bookmarklet as new data is loaded.

Using Google Geocoding API in Python

Started work on a wrapper for the Google Geocoding API, called pygeocoding. Check out the Github page for the code and usage.

The intent is to provide a Pythonistic interface in building your Google Maps such as building a Google Map in Django with locations stored in your models. As noted on the API page:

Note: the Geocoding API may only be used in conjunction with a Google map; geocoding results without displaying them on a map is prohibited. For complete details on allowed usage, consult the Maps API Terms of Service License Restrictions.

Some example usage:

import pygeocoding

# Let's find CERN
pygeocoding.LookUp(address="CERN CH-1211 Genève 23 Switzerland")
{u'status': u'OK', u'results': [{u'geometry': {u'location_type': u'APPROXIMATE', # ... truncated output

# We can also search backwards - let's pipe in the lat/long of the liberty bell (approximately)
# - we'll just see what the first result is
r = pygeocoding.LookUp(latlng="39.9518819802915,-75.1476150197085")

# now we can pipe these results to our mapping functions

Post to Facebook with Python

Let’s take a quick look at a great tool to post to Facebook from Python called fbconsole. It’s fairly self explanatory, so I won’t bother going into much textual detail here. I’ll take you through some of the basic features and highlight as we go. In the following code snippet, we will post some data to our personal status feed, similar to how we push from KindleQuotes to Facebook when a user would like to share an item.

import fbconsole as F

# If you have an APP ID from Facebook, you can add that here.
# Otherwise, you will be posting as fbconsole.
F.APP_ID = '<YOURID>'

# Set some authentication parameters
# Here we will set the ability to publish to a stream
F.AUTH_SCOPE = ['publish_stream']

# Now we will login and get our OAuth token.
F.authenticate()

# After successful login, we can add our status update.
# Let's assume we have some neat data we want to push to the stream.
# We'll post our world_changing_data to our personal feed
F.post('/me/feed', {'message': world_changing_data})

# Want to logout and wipe your OAuth token?
F.logout()

We just completed a very simple data push to our Facebook status feed from within our python program. There is a lot more functionality to check out once you have the basic setup working in your program.

Stumpy Version 1.5 is Now Available!

Stumpy Version 1.5 is now out and ready for testing.
Should be functional, but please submit any issues you might find to the issues page.

Changes include (from commits):

  • Removed hardcoded domains from JS. We now pipe in through the stumpy_domain var by setting a global JS var ‘DOMAIN’ in the index and then reference that JS var in our scripts. You will no longer need to set your domain as hard coded into javascript code.
  • Updated to use get submission of new URLs for shortening. This should work, but needs to be tested on the production version to make sure WSGI and such are working okay without the earlier hack that was implemented.

Accessing Django Template Variables in Javascript

How do we follow the Django DRY principle and avoid as many hard coded elements as possible in our project when we need to include Javascript? A good example of this is if we are pulling in a bookmarklet that will be offered on the site. We need to reference the domain of our project in the bookmarklet, but this then yields code buried in our project’s static files that needs to be altered by anyone that might be utilizing your open sourced code.

This example presents a little bit of a challenge. If this were HTML in our template we could simply reference a DOMAIN variable that we would feed in through a view. However, this is a static Javascript file, so how do we go about utilizing Django template variables in supposedly static Javascript?

Here is a simple method. In our HTML template, we will setup a Javascript global variable that is created to reference a template variable that we feed in from our view, here a domain, and this variable is then referenced in our static Javascript files.

<!-- Our HTML Template (templates/index.html) that is fed data from views.py -->
{% extends "base.html" %}
{% block content %}

<script type="text/javascript" src="/static/somejs.js"></script>

<script> 
var DOMAIN = "{{ site_domain }}";
</script>

<!-- rest of our template, business as usual. -->
{% endblock %}

As you can see, we would feed in a site_domain variable from views.py that might be created something like this.

from django.contrib.sites.models import Site
from django.shortcuts import render_to_response

def index(request):
    '''Our main index view.'''
    site_domain = smart_str(Site.objects.get_current().domain)
    # more of our view code...
    
    return render_to_response('templates/index.html', {
	'site_domain': site_domain,
        #...rest of our template vars
    })

Now, how do we use this in our static Javascript? We reference that global Javascript variable we declared in our template using our Django template variable site_domain.

// Our Javascript file ... /static/somejs.js 
alert("Your current domain is: "+DOMAIN);

Now our code is much more portable, even in places where things should essentially be static.

Cleansing HTML in Django Forms

We want to accept some HTML, while stripping out the rest, in our Django form. Let’s take a quick look at how we can introduce some basic HTML cleaning functionality to our Django ModelForm. We will be using Bleach to do all the dirty work.

from yourapp.models import YourModel
from django import forms
import bleach

class YourForm(ModelForm):
    class Meta:
        model = YourModel
    
    def bleachData(self, data, whitelist=[]):
        allowed = whitelist
        clean_data = bleach.clean(data, allowed)

        return clean_data

    def clean_somefield(self):
        somefield = self.cleaned_data['somefield']
        whitelist = ['b', 'i']
        somefield = self.beachData(somefield, whitelist)

        return somefield 

    def clean(self):
        cleaned_data = super(YourForm, self).clean()
        self.cleaned_data['somefield'] = self.clean_somefield()

        return self.cleaned_data

As you can see, we run our normal form validation methods and then initiate a post-cleanse cleanse by bleaching ‘somefield’ and allowing a whitelist of tags, bold and italics.

Getting Audio Information in Python

Want to grab some basic audio file information in your Python program?

Let’s use Mutagen to look at the type, length, and size of an audio element.

import mutagen

class Audio:
    pass

f = "some_audio.m4a"
element = mutagen.File(f)

if element:
    Audio.format_list = element._mimes
    Audio.size = element.size
    Audio.length = element.length
else:
    Audio.error = "Invalid audio file."

Here, we could have imported the M4A handler, but using the File class we don’t have to make audio type assumptions a priori. If the audio format cannot be handled or is invalid, we will simply get a None Type return when sending our file to the File class.