Skip to content
This repository has been archived by the owner on Mar 20, 2019. It is now read-only.

Commit

Permalink
add get_file_info method and MovieHasher to search for movies based o…
Browse files Browse the repository at this point in the history
…n the OpenSubtitles file hash
  • Loading branch information
jduff committed Mar 13, 2011
1 parent 87e6d5e commit e1a67bd
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 3 deletions.
16 changes: 14 additions & 2 deletions lib/tmdb_party.rb
@@ -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

Expand Down Expand Up @@ -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)
Expand Down
32 changes: 32 additions & 0 deletions lib/tmdb_party/extras/movie_hasher.rb
@@ -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
21 changes: 21 additions & 0 deletions spec/lib/tmdb_party/extras/movie_hasher_spec.rb
@@ -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
20 changes: 19 additions & 1 deletion spec/lib/tmdb_party_spec.rb
Expand Up @@ -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
Expand Down Expand Up @@ -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.