Permalink
Browse files

add get_file_info method and MovieHasher to search for movies based o…

…n the OpenSubtitles file hash
  • Loading branch information...
1 parent 87e6d5e commit e1a67bdbd1f003cbb590f6ca9bbfec639616566d @jduff committed Mar 13, 2011
View
@@ -1,6 +1,6 @@
require 'httparty'
-%w[extras/httparty_icebox extras/attributes video genre person image country studio cast_member movie].each do |class_name|
+%w[extras/httparty_icebox extras/attributes video genre person image country studio cast_member movie extras/movie_hasher].each do |class_name|
require "tmdb_party/#{class_name}"
end
@@ -49,7 +49,19 @@ def get_info(id, lang = @default_lang)
data = self.class.get(method_url('Movie.getInfo', lang, id)).parsed_response
Movie.new(data.first, self)
end
-
+
+ def get_file_info(file, lang=@default_lang)
+ hash = TMDBParty::MovieHasher.compute_hash(file)
+ bytesize = file.size
+ data = self.class.get(method_url('Media.getInfo', lang, hash, bytesize)).parsed_response
+
+ if data.class != Array || data.first == "Nothing found."
+ []
+ else
+ data.collect { |movie| Movie.new(movie, self) }
+ end
+ end
+
def get_person(id, lang = @default_lang)
data = self.class.get(method_url('Person.getInfo', lang, id)).parsed_response
Person.new(data.first, self)
@@ -0,0 +1,32 @@
+# MovieHasher based on the one found here:
+# http://trac.opensubtitles.org/projects/opensubtitles/wiki/HashSourceCodes
+#
+# This will compute a unique hash for the movie that can be used for lookups on TMDB
+# The algorithm calculates size + 64bit chksum of the first and last 64k (even if they overlap because the file is smaller than 128k).
+# Make sure to uncomment and run the tests for this before making any changes
+module TMDBParty
+ module MovieHasher
+ CHUNK_SIZE = 64 * 1024 # in bytes
+
+ def self.compute_hash(file)
+ filesize = file.size
+ hash = filesize
+
+ # Read 64 kbytes, divide up into 64 bits and add each
+ # to hash. Do for beginning and end of file.
+ # Q = unsigned long long = 64 bit
+ file.read(CHUNK_SIZE).unpack("Q*").each do |n|
+ hash = hash + n & 0xffffffffffffffff # to remain as 64 bit number
+ end
+
+ file.seek([0, filesize - CHUNK_SIZE].max, IO::SEEK_SET)
+
+ # And again for the end of the file
+ file.read(CHUNK_SIZE).unpack("Q*").each do |n|
+ hash = hash + n & 0xffffffffffffffff
+ end
+
+ sprintf("%016x", hash)
+ end
+ end
+end
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+# Download the sample files from here:
+# http://trac.opensubtitles.org/projects/opensubtitles/wiki/HashSourceCodes
+# and uncomment these tests before making any changes
+describe TMDBParty::MovieHasher do
+ # Not sure the best way to have tests for this without having real files to work with.
+ it "should compute hash" do
+ pending
+ File.open('breakdance.avi') do |file|
+ TMDBParty::MovieHasher.compute_hash(file).should == "8e245d9679d31e12"
+ end
+ end
+
+ it "should compute hash on large file" do
+ pending
+ File.open('dummy.bin') do |file|
+ TMDBParty::MovieHasher.compute_hash(file).should == "61f7751fc2a72bfb"
+ end
+ end
+end
@@ -65,6 +65,24 @@
tmdb.get_info(1858, 'sv').should_not be_nil
end
end
+
+ describe "#get_info with file" do
+ it "should return a movie instance" do
+ file = mock("file")
+ file.should_receive(:size).and_return(742086656)
+ TMDBParty::MovieHasher.should_receive(:compute_hash).with(file).and_return("907172e7fe51ba57")
+ stub_get('/Media.getInfo/en/json/key/907172e7fe51ba57/742086656', 'transformers.json')
+ tmdb.get_file_info(file).should have(1).movies
+ end
+
+ it "should return empty array when no movie found" do
+ file = mock("file")
+ file.should_receive(:size).and_return("fake")
+ TMDBParty::MovieHasher.should_receive(:compute_hash).with(file).and_return("fake")
+ stub_get('/Media.getInfo/en/json/key/fake/fake', 'nothing_found.json')
+ tmdb.get_file_info(file).should == []
+ end
+ end
describe "#search_person" do
it "should return empty array when no people was found" do
@@ -114,4 +132,4 @@
tmdb.get_genres('sv').first.name.should == 'Action'
end
end
-end
+end

0 comments on commit e1a67bd

Please sign in to comment.