Jinni is going away: export your ratings!

Jinni was an awesome movie recommendation service - actually, it was the only service that was able to accurately predict if movie will suit my taste or not.

Alas, good things are not meant to last, and recently they announced that they will be shutting down the service and will be instead focusing on providing targeted ads for TV. They do promise that they will e-mail users their rating history once the site goes down, but I can't trust them about that - I care about my movie list too much. So I needed to export ratings myself, to be extra sure.

Jinni doesn't provide any automated export service (at least, I failed to find one). Since copying several hundred ratings by hand would be tedious, I decided to throw together a simple script, that other Jinni users may find useful.

First, we need to talk about authentication to Jinni server. In this case, when I say "authentication", I rather mean lack of it - because all you need is to add "auth=Username" cookie to your request. So the following will get you the first page of my ratings:
curl http://www.jinni.com/user/Rogach/ratings -H "Cookie: auth=Rogach"
Not like I care much about privacy, but it is still funny.

The second part is about actual layout of our data on the page. Film rows don't have special CSS class for them, they only have ids of the form "ratings_rowX", where X goes from 0 to 19. Thus we will have to iterate those ids instead of simply extracting required rows by class.

Here's the script. Don't forget to change 34 to number of pages in your ratings!
# We'll be using Nokogiri - awesome gem to parse HTML and query it using CSS selectors

def get_jinni_ratings(page)
  uri = URI.parse("http://www.jinni.com/user/Rogach/ratings") # change to your username
  http = Net::HTTP.new(uri.host, uri.port)
  request = Net::HTTP::Post.new(uri.request_uri)
  request.add_field("Cookie", "auth=Rogach") # also change to your username
  request.set_form_data({ "pagingSlider_index" => page })

ratingTranslation = {
  0 => "Not For Me",
  1 => "Awful",
  2 => "Bad",
  3 => "Poor",
  4 => "Disappointing",
  5 => "So-so",
  6 => "Okay",
  7 => "Good",
  8 => "Great",
  9 => "Amazing",
  10 => "Must See"

# change 34 to number of the last page in your rating list
(1..34).each { |pageIdx|
  page = get_jinni_ratings(pageIdx)
  (0..19).each { |itemIdx|
    title = page.css("#ratings_row" + String(itemIdx) + " .ratings_cell2").attr("title").text.strip
    rating = page.css("#ratings_row" + String(itemIdx) + " .ratings_cell3 script").text.strip.match(/RatedORSuggestedValue: (\d+)/)[1].to_i
    descr = ratingTranslation[rating]
    puts "#{title}\t#{rating}\t#{descr}"
This script will print all your ratings in tab-separated format to stdout. Hope it will help someone!


  1. Hey thanks for this, this is exactly what I want to do. Unfortunately I'm a total script noob - any chance you could run this for me on the username "beniawiuuw" and post a link here? I have 28 pages of ratings. I'd be eternally grateful!

    1. Here you go: http://pastie.org/10262001
      Note that your username should begin with capital letter (Beniawiuuw) instead of all lowercase - that gave me errors at the first try.

  2. What service are we supposed to use now?

    1. Unfortunately, I haven't seen any service that will come even remotely close to quality of jinni's recommendations.

    2. I tried Criticker, and prediction and recommendation quality is awful. Imported 233 film ratings, correlation between my ratings and predictions is -0.001738026 - meaning no correlation at all. Maybe I'm just some outlier, but for me Jinni's prediction quality was *much* better.

  3. what is the use of exporting if there is not site that will allow import of the ratings?

    1. The original idea was to save your rating history - for example, I rated over 600 films and often use that history to recommend films to friends or sometimes re-watch some awesome movie.
      But currently I'm exploring criticker.com, and if it turns out to be useful enough, I might write import script for it - stay posted!


Post a Comment

Popular posts from this blog

How to create your own simple 3D render engine in pure Java

Solving quadruple dependency injection problem in Angular

Configuration objects in Scallop