tvdbr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in tvdbr.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,27 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ tvdbr (0.0.1)
5
+ activesupport
6
+ hashie
7
+ httparty
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ activesupport (3.0.3)
13
+ crack (0.1.8)
14
+ hashie (0.4.0)
15
+ httparty (0.6.1)
16
+ crack (= 0.1.8)
17
+ rake (0.8.7)
18
+
19
+ PLATFORMS
20
+ ruby
21
+
22
+ DEPENDENCIES
23
+ activesupport
24
+ hashie
25
+ httparty
26
+ rake
27
+ tvdbr!
data/README ADDED
@@ -0,0 +1,70 @@
1
+ # 1. Associate our media with tvdb
2
+ # 2. Iterate through and search episodes (backfill missing episodes, backfill better screenshots)
3
+ # 3. Update rake task, daily => get all the updates, reference the changes => propogate to our data (new episodes, new shows)
4
+
5
+ # rake tvdb:populate => associate media to tvdb and backfill missing episodes and show info
6
+
7
+ Media.tvdb_id_is_null.find_each do |media|
8
+ tvdb_match = tvdb.fetch_series_from_data(:title => media.title, :starring => media.starring)
9
+ # Update media info and/or associate media to tvdb (ref_id) and change source
10
+ media.update_attributes(:source => "Tvdb", :tvdb_id => tvdb_match.id)
11
+ tvdb_match.episodes.each do |tvdb_episode|
12
+ episode = media.episodes.where(:episode => tvdb_episode.episode_num, :season => tvdb_episode.season_num)
13
+ # Update or create episode from the information from tvdb
14
+ end
15
+ end
16
+
17
+ # rake tvdb:daily => update database to sync with new shows and episodes on a daily task (attach existing show)
18
+
19
+ tvdb.each_updated_series(:since => 1.day.ago) do |tvdb_series|
20
+ puts "#{series.id} - #{series.title}"
21
+ media = Media.where(:ref_id => tvdb_series.id).first
22
+ # Update information from the new data?
23
+ end
24
+
25
+ tvdb.each_updated_episode(:since => 1.day.ago) do |tvdb_episode|
26
+ media = Media.where(:ref_id => tvdb_series.seriesid).first
27
+ episode = Episode.where(:season => tvdb_episode.season_num, :episode => tvdb_episode.episode_num).first
28
+ # Update or create episode information based on the new data.
29
+ end
30
+
31
+ == Initial Database Processing
32
+
33
+ - Get the current server time
34
+ a. Retrieve http://www.thetvdb.com/api/Updates.php?type=none. (Time.now.to_i) [1295299577]
35
+ b. Store this value for later use (denoted as <previoustime> for rest of example).
36
+
37
+ - Loop through and look up each series id
38
+ a. Retrieve http://www.thetvdb.com/api/GetSeries.php?seriesname=<series name from your database>
39
+ b. Optionally present results to user so they can select the match they want.
40
+ c. Store this series id in a table in your database.
41
+
42
+ - Get base information for each series
43
+ a. Retrieve <mirrorpath_zip>/api/<apikey>/series/<seriesid>/all/<language>.zip and extract <language>.xml and banners.xml.
44
+ b. Process the XML data in <language>.xml and store all <Series> data.
45
+ c. Download each series banner in banners.xml and prompt the user to see which they want to keep.
46
+ Note: Make sure you record <id> from each series, since it's returned in updates as <Series>.
47
+
48
+ - Get base information for each episode
49
+ a. Use <language>.xml from step 3 to find and store the data associated with your episode.
50
+ b. Use <filename> from results in step above to download the episode image from <mirrorpath_banners>/banners/<filename>.
51
+ Note: Make sure you record <id> from each episode, since it's returned in updates as <Episode>.
52
+
53
+ == Future Database Processing
54
+
55
+ These steps are used to keep your database current with the latest information.
56
+
57
+ - Get a list of all series and episode updates
58
+ a. Retrieve http://www.thetvdb.com/api/Updates.php?type=all&time=<previoustime>.
59
+ b. Process the returned XML and loop through each series (<seriesid>) and episode (<episodeid>) entry.
60
+
61
+ - Update each series in the update XML
62
+ a. Retrieve <mirrorpath_xml>/api/<apikey>/series/<seriesid>/<language>.xml.
63
+ b. Process XML data and use to replace information in local database.
64
+
65
+ - Update each episode in the update XML
66
+ a. Retrieve <mirrorpath_xml>/api/<apikey>/episodes/<episodeid>/<language>.xml.
67
+ b. Process XML data and use to replace information in local database.
68
+
69
+ - Record <previoustime> for next update
70
+ a. Using the XML from step 2, store <Time> as <previoustime> and use for your next call to Updates.php.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/examples/demo.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'rubygems'
2
+ require 'tvdbr'
3
+
4
+ tvdb = Tvdbr::Client.new('YOUR_API_KEY')
5
+
6
+ # Fetch series based on title and starring
7
+ series_wrong = tvdb.fetch_series_from_data(:title => "Dexter",
8
+ :starring => "Adewale Akinnuoye-Agbaje, Sam Anderson, Naveen Andrews, L. Scott Caldwell, Nestor Carbonell, François Chau, Henry Ian Cusick, Jeremy Davies, Emilie de Ravin, Michael Emerson, Jeff Fahey, Fionnula Flanagan, Matthew Fox, Jorge Garcia, Maggie Grace, Josh Holloway, Malcolm David Kelley, Daniel Dae Kim, Yunjin Kim, Ken Leung, Evangeline Lilly, Rebecca Mader, Elizabeth Mitchell, Dominic Monaghan, Terry O'Quinn, Harold Perrineau, Zuleikha Robinson, Michelle Rodriguez, Kiele Sanchez,Rodrigo Santoro, Ian Somerhalder, John Terry, Sonya Walger, Cynthia Watros")
9
+ puts "Wrong Match: #{series_wrong.inspect}"
10
+
11
+ # Fetch series based on title and starring
12
+ series_right = tvdb.fetch_series_from_data(:title => "Lost",
13
+ :starring => "Adewale Akinnuoye-Agbaje, Sam Anderson, Naveen Andrews, L. Scott Caldwell, Nestor Carbonell, François Chau, Henry Ian Cusick, Jeremy Davies, Emilie de Ravin, Michael Emerson, Jeff Fahey, Fionnula Flanagan, Matthew Fox, Jorge Garcia, Maggie Grace, Josh Holloway, Malcolm David Kelley, Daniel Dae Kim, Yunjin Kim, Ken Leung, Evangeline Lilly, Rebecca Mader, Elizabeth Mitchell, Dominic Monaghan, Terry O'Quinn, Harold Perrineau, Zuleikha Robinson, Michelle Rodriguez, Kiele Sanchez,Rodrigo Santoro, Ian Somerhalder, John Terry, Sonya Walger, Cynthia Watros")
14
+ puts "Right Match: #{series_right.inspect}"
15
+
16
+ puts "\n\n"
17
+ series = series_right
18
+ puts series.title + " (" + series.categories.join(", ") + ")"
19
+ puts series.synopsis
20
+ puts series.starring.join(", ")
21
+ puts series.poster
22
+ puts series.release_date.inspect
23
+
24
+ # Fetch episodes for a series
25
+ puts "\nEpisodes:\n\n"
26
+ series.episodes.each do |e|
27
+ puts e.name + " (S#{e.season_num}E#{e.episode_num})"
28
+ end
29
+
30
+ # # Fetch series updates since given timestamp
31
+ # results = tvdb.find_updates_since(2.hours.ago)
32
+ # puts "\n\nUpdated series since 2 hours ago: #{results[:series].size} series\n\n"
33
+ # tvdb.each_updated_series(:since => 2.hours.ago) do |series|
34
+ # puts "#{series.id} - #{series.title}"
35
+ # end
36
+ #
37
+ # # Fetch episode udpates since given timestamp
38
+ # puts "Updated episodes since 2 hours ago: #{results[:episodes].size} episodes\n\n"
39
+ # tvdb.each_updated_episode(:since => 2.hours.ago) do |episode|
40
+ # puts "#{episode.id} - #{episode.name} - #{episode.seriesid}"
41
+ # end
@@ -0,0 +1,123 @@
1
+ require 'httparty' unless defined?(HTTParty)
2
+
3
+ module Tvdbr
4
+ class Client
5
+ include HTTParty
6
+ format :xml
7
+ base_uri "http://www.thetvdb.com/api/"
8
+
9
+ # Creates an instance of the TVDB interface
10
+ # Tvdb.new('some_key')
11
+ def initialize(api_key)
12
+ @api_key = api_key
13
+ check_api_key!
14
+ end
15
+
16
+ # Fetches a series object based on the given attributes hash
17
+ # tvdb.fetch_series_from_data(:title => "Dexter", :kind => "TvShow", :starring => "xxxx, xxxx")
18
+ # => { "SeriesName" => "Dexter", ... } or nil
19
+ #
20
+ def fetch_series_from_data(options={})
21
+ return self.find_series_by_title(options[:title]) if options[:starring].nil?
22
+ series_results = self.find_all_series_by_title(options[:title])
23
+ expected_actors = options[:starring].split(",")
24
+ series_results.find { |series| series.actor_match?(expected_actors) }
25
+ end
26
+
27
+ # Yields the block for every updated series
28
+ # tvdb.each_updated_series(:since => 1.day.ago) { |s| Media.find_by_tvdb_id(s.id).title = s.title }
29
+ def each_updated_series(options={}, &block)
30
+ updates = self.find_updates_since(options[:since])
31
+ updates[:series].each do |series_id|
32
+ series = Series.new(self, self.find_series_by_id(series_id))
33
+ block.call(series)
34
+ end
35
+ end
36
+
37
+ # Yields the block for every updated episode
38
+ # tvdb.each_updated_episode(:since => 1.day.ago) { |s| Episode.find_by_tvdb_id(s.id).title = s.title }
39
+ def each_updated_episode(options={}, &block)
40
+ updates = self.find_updates_since(options[:since])
41
+ updates[:episodes].each do |episode_id|
42
+ episode = Episode.new(self, self.find_episode_by_id(episode_id))
43
+ block.call(episode)
44
+ end
45
+ end
46
+
47
+ # Returns all series matching the given title
48
+ # tvdb.find_all_series_by_title("Dexter")
49
+ # => [{ "SeriesName" => "Dexter", ... }, ...]
50
+ def find_all_series_by_title(title)
51
+ result = self.class.get("/GetSeries.php", :query => { :seriesname => title, :language => "en" })['Data']
52
+ return [] if result.blank? || result['Series'].blank?
53
+ result = result['Series'].is_a?(Array) ? result['Series'] : [result['Series']]
54
+ result.first(5).map { |s| Series.new(self, self.find_series_by_id(s['seriesid'])) }
55
+ end
56
+
57
+ # Returns the first series returned for a title
58
+ # tvdb.find_series_by_title("Dexter")
59
+ # => { "SeriesName" => "Dexter", ... }
60
+ #
61
+ def find_series_by_title(title)
62
+ self.find_all_series_by_title(title).first
63
+ end
64
+
65
+ # Returns series data for a given series_id
66
+ # tvdb.find_series_by_id(1234, :all => true)
67
+ # tvdb.find_series_by_id(1234, :dataset => true)
68
+ # => { "SeriesName" => "Dexter", ... }
69
+ def find_series_by_id(series_id, options={})
70
+ series_url = "/series/#{series_id}"
71
+ series_url << "/all" if options[:all]
72
+ result = self.get_with_key(series_url)['Data']
73
+ return result if options[:all]
74
+ return Series.new(self, result["Series"]) if options[:dataset]
75
+ result["Series"]
76
+ end
77
+
78
+ # Returns Episode data for a given episode id
79
+ # tvdb.find_episode_by_id(12345)
80
+ # => { "EpisodeName" => "..." }
81
+ def find_episode_by_id(episode_id, options={})
82
+ episode_url = "/episodes/#{episode_id}"
83
+ result = self.get_with_key(episode_url)['Data']
84
+ return Episode.new(self, result["Episode"]) if options[:dataset]
85
+ result["Episode"]
86
+ end
87
+
88
+ # Returns the list of TVDB mirror_urls
89
+ # => ["http://thetvdb.com", ...]
90
+ def mirror_urls
91
+ Array(self.get_with_key('/mirrors.xml')['Mirrors']['Mirror']['mirrorpath'])
92
+ end
93
+
94
+ # Returns a list of series and episode updates since given time
95
+ # tvdb.find_updates_since(1.day.ago)
96
+ # => { :series }
97
+ # {"Time"=>"1295300137", "Series"=>["70386", "70500", "70522", "70566", "70591", "70726", "70730", "70761", "70851", "70994", "71035", "71179", "71355",
98
+ #{ }"71383", "71394", "71470", "71489", "71493", "71635", "71649", "71663", "71753", "71788", "71991", "72023", "72073", "222571", "72158", "72164",
99
+ #{ }"72201", "72218", "72227", "72229", "72231", "72233", "72235", "72301", "72368", "72382", "72449", "72467", "72476", "72514", "72546", "153021", "72614", "72675", "72716", "72745", "82812", "72888", "72922", "72955", "72963", "80348", "73014", "73028", "73029", "73141", "222641", "73244", "73255", "207621", "73265", "73388", "73444", "73507", "73508", "73534", "73545", "73546", "73587", "73641", "73696", "73704", "73730", "73739", "83004", "73741", "73762", "73776", "73787", "73800", "73838", "73871", "73888", "73902", "73918", "73965", "74156", "74205", "74285", "74340", "74379", "164221", "74523", "74550", "74608", "74670", "74697", "74709", "74730", "74806", "74814", "74843", "74852", "74875", "74897", "74948", "74992", "219931", "75062", "75138", "75164", "75299", "75340", "75382", "75397", "75450", "75457", "75532", "75579", "75669", "75682", "75692", "75710", "124561", "75719", "75734", "75760", "75897", "75931", "75978", "82467", "76107", "76168", "76177", "76290", "180791", "76354", "76355", "76360", "76385", "163531", "76421", "76568", "76575", "76648", "76738", "76746", "76772", "76813", "76846", "76857", "76924", "77098", "77244", "77398", "77526", "77537", "77544", "77623", "219821", "77772", "77811", "126301", "77847", "77996", "78056", "222821", "78131", "78224", "85075", "78261", "78310", "78442", "78490", "78527", "78581", "78650", "78733", "78804", "84352", "78817", "78833", "78875", "78890", "78901", "209551", "78923", "78929", "78939", "78949", "79022", "79089", "79114", "79126", "80392", "163851", "79168", "79169", "79175", "72108", "79182", "109411", "79203", "79212", "79216", "107931", "79251", "79261", "79262", "82459", "79317", "79330", "82881", "79334", "79335", "79337", "79349", "79352", "79488", "79501", "79506", "79507", "79511", "79525", "79567", "79572", "79696", "79809", "79676", "80128", "222701", "79824", "79834", "79842", "85358", "79899", "79890", "79925", "80033", "80115", "80159", "80207", "80198", "80231", "80273", "80270", "80301", "80389", "80310", "80330", "80337", "80349", "80367", "80379", "80411", "80442", "80494", "102241", "80529", "80542", "80547", "80608", "80680", "80732", "80846", "80976", "80988", "80995", "81148", "81074", "81161", "222601", "81189", "93651", "81213", "81230", "81253", "221561", "221481", "81335", "81346", "81400", "81797", "81385", "81386", "81394", "222801", "222811", "222831", "81445", "81831", "81578", "95441", "81751", "81841", "81869", "81955", "81950", "82046", "85186", "82038", "82083", "82066", "82339", "82184", "82283", "82213", "82422", "82480", "82493", "82696", "82620", "82613", "138551", "82716", "82825", "103121", "83098", "83115", "83123", "83214", "83237", "83268", "83292", "83322", "83462", "83558", "83602", "83610", "83616", "83742", "109061", "83929", "84021", "84024", "84238", "84358", "84458", "84600", "84676", "84879", "84912", "84947", "85040", "85523", "85539", "222711", "222621", "222631", "222651", "222661", "88031", "91171", "91311", "94971", "92411", "93221", "93991", "213491", "94121", "94541", "94571", "94801", "94991", "95011", "95021", "95451", "95491", "95731", "95761", "97281", "97401", "97731", "98411", "100071", "164541", "101181", "102441", "109931", "112621", "113471", "114701", "114851", "114921", "116861", "117411", "118021", "118421", "222131", "119761", "120431", "123581", "124051", "127021", "127401", "128141", "128171", "129261", "131561", "132941", "133251", "133461", "133861", "134241", "134321", "134511", "136621", "163561", "163581", "137031", "138531", "140141", "142101", "142581", "142961", "145191", "145231", "145951", "146711", "146911", "148151", "149731", "154431", "158661", "158411", "159791", "160671", "161461", "161511", "163431", "163671", "164301", "164401", "164951", "164981", "183971", "165591", "165841", "165851", "166361", "166981", "168941", "171241", "174501", "172501", "173821", "174921", "175861", "176941", "178201", "180831", "181011", "182061", "182661", "188201", "186911", "187071", "190531", "220661", "219391", "192171", "192601", "193131", "194031", "194051", "194541", "199051", "194751", "195161", "195611", "196921", "197021", "197271", "200301", "201481", "201991", "203261", "203411", "206011", "207391", "207701", "208231", "208291", "209671", "211391", "212421", "212571", "213721", "214921", "216181", "217331", "217661", "217961", "218191", "218891", "218991", "219131", "219701", "219771", "220141", "220621", "220551", "220571", "221001", "221771", "221801", "222671", "222681", "222581", "222561", "222691", "222721", "222731", "222741", "222751", "222761", "222771", "222781", "222791"], "Episode"=>["3411341", "6112", "6113", "6114", "6115", "6116", "6117", "6118", "6119", "6120", "6121", "6122", "6123", "6124", "6125", "6126", "6127", "6128", "6131", "6132", "6133", "6134", "6135", "6136", "6137", "6138", "6139", "6140", "6141", "6142", "6143", "6144", "6145", "6146", "6147", "6148", "6149", "6150", "6151", "6152", "19486", "19487", "19488", "19489", "19490", "19491", "19492", "19493", "19494", "19495", "19496", "19497", "19498", "19499", "19500", "19501", "19502", "19503", "19504", "19505", "19506", "19507", "19508", "19509", "19510", "19511", "19512", "19513", "19514", "19515", "19516", "19517", "19518", "19519", "19520", "19521", "19522", "19523", "19524", "19525", "19526", "19527", "19528", "19529", "19530", "19531", "19532", "19533", "19534", "19535", "19536", "19537", "19538", "19539", "19540", "19541", "19542", "19543", "19544", "19545", "19546", "19547", "19548", "19549", "19550", "19551", "19552", "19553", "19554", "19555", "19556", "19557", "19558", "19559", "19560", "19561", "19562", "19563", "19564", "19565", "19566", "19567", "19568", "19569", "19570", "19571", "19572", "19573", "19574", "19575", "19576", "19577", "19578", "19579", "19580", "19581", "19582", "19583", "19584", "19585", "19586", "19587", "19588", "19589", "19590", "19591", "19592", "19593", "19594", "19595", "19596", "78538", "85905", "85906", "85907", "85908", "85909", "85910", "85911", "85912", "85913", "85914", "85916", "85917", "85918", "85919", "85920", "85921", "85922", "85923", "85924", "87055", "87056", "87057", "87058", "87059", "87060", "87061", "87062", "87063", "87064", "87065", "87066", "87067", "87068", "87069", "87070", "87071", "87072", "87073", "87074", "87075", "87076", "87077", "87078", "87081", "87082", "87083", "87084", "87085", "87086", "87087", "87088", "87089", "87090", "87091", "87092", "87093", "87094", "87095", "87096", "87097", "87098", "87099", "87100", "87101", "87102", "87103", "87104", "87130", "87132", "87133", "87134", "87135", "87136", "87137", "87138", "87139", "87140", "87141", "87142", "87143", "87144", "87145", "87146", "87147", "87148", "87150", "87151", "87152", "87153", "87154", "87155", "87156", "87157", "87158", "87159", "87160", "87161", "87162", "87163", "87164", "87165", "87167", "87168", "87169", "87170", "87172", "87173", "87175", "87176", "93515", "93516", "93517", "93518", "93519", "93520", "93521", "93522", "93523", "93524", "93525", "93526", "93527", "93528", "93529", "93530", "93531", "93532", "93533", "93534", "93535", "93536", "93537", "104003", "104004", "104005", "104099", "104100", "104101", "104102", "104103", "104104", "104105", "104106", "104107", "104108", "104109", "104111", "104112", "104113", "104114", "104115", "104116", "104117", "104118", "104119", "104120", "104121", "104122", "117690", "117691", "2275781", "131481", "131482", "131483", "131484", "131485", "131486", "131487", "131488", "131489", "131490", "131491", "131492", "131493", "131494", "131495", "131496", "147906", "147908", "151219", "159329", "159330", "165527", "165531", "165533", "165544", "165545", "165549", "165551", "165552", "165554", "165555", "165556", "165557", "165558", "165559", "165560", "165561", "165562", "165563", "165564", "165565", "175245", "175246", "175247", "175248", "175249", "175332", "175333", "175335", "175337", "175339", "175340", "200336", "200337", "200338", "200339", "200340", "200341", "200342", "383455", "383456", "3490541", "214197", "214198", "214200", "3088411", "214219", "789101", "228957", "228958", "228959", "228960", "228961", "228962", "228963", "228964", "228965", "228966", "228967", "228969", "228970", "228971", "228972", "228973", "228974", "228975", "228976", "228977", "228978", "228979", "228980", "228981", "228982", "228983", "228984", "228985", "228986", "228987", "228988", "228989", "228990", "228991", "228992", "228993", "228994", "228995", "228996", "228997", "228998", "228999", "229000", "229001", "229002", "229003", "229004", "229005", "229006", "229007", "229008", "229009", "229010", "229011", "229012", "229013", "229014", "229015", "229016", "229017", "229018", "229019", "229020", "229021", "229022", "229023", "229024", "229025", "229026", "229027", "229028", "229029", "229030", "229031", "229032", "229033", "229034", "229035", "229036", "229037", "229038", "229039", "229040", "229041", "229042", "229043", "229044", "229045", "229046", "229047", "229048", "229049", "229050", "229051", "229052", "229053", "229054", "229055", "229056", "229057", "229058", "229059", "229060", "229061", "229062", "2588861", "229065", "229066", "229067", "235252", "248787", "248788", "2226501", "277955", "277956", "277957", "277958", "277959", "277960", "277961", "277962", "277963", "277964", "277965", "285172", "285173", "285174", "285175", "297130", "297131", "297132", "297133", "297134", "2562291", "299427", "299428", "299429", "299430", "299431", "299432", "299433", "299600", "299602", "299603", "299604", "315500", "315501", "3406411", "304964", "304965", "304966", "304967", "304968", "324294", "315503", "315504", "315505", "315506", "315507", "315508", "315509", "315510", "2428991", "328515", "328516", "328517", "328518", "328519", "328520", "328521", "328522", "328523", "328524", "328611", "328612", "328613", "328614", "328615", "328616", "328617", "328618", "328619", "328620", "328621", "328622", "328623", "328624", "328625", "329990", "329991", "329992", "329993", "333410", "333608", "333609", "1543481", "1543491", "1543501", "339789", "339791", "339792", "339805", "339814", "348267", "348268", "348270", "349232", "349233", "349235", "349236", "349238", "353644", "353645", "353646", "353647", "353648", "392706", "392707", "392708", "369273", "369857", "371998", "377868", "377869", "392140", "392139", "391671", "383603", "385744", "386664", "386673", "388126", "388260", "403429", "403430", "403431", "405995", "412351", "412482", "3489821", "3489801", "413385", "413386", "413387", "413388", "438912", "440482", "440483", "446898", "3489811", "450261", "450271", "450281", "450291", "450301", "450311", "450321", "466681", "480481", "480471", "480461", "480491", "480501", "529461", "529481", "529491", "529531", "529541", "529571", "529591", "529601", "529611", "582801", "582811", "582831", "582841", "3469021", "641491", "641501", "641511", "641521", "641531", "641541", "641551", "641561", "641571", "641581", "641591", "641601", "641611", "695171", "705231", "705261", "705271", "705281", "705301", "705311", "3489791", "738671", "3490561", "3489931", "3489941", "3489951", "797321", "863841", "863851", "2502511", "2502521", "2502531", "918261", "918271", "2420141", "960411", "970951", "3488721", "1007721", "1122641", "1046501", "1046511", "1046521", "1046811", "1056501", "1069101", "1073491", "1073501", "1073511", "1079401", "1079411", "1129781", "1129801", "1129811", "1129831", "1133991", "1147201", "1147211", "1147231", "1156901", "1163221", "1164561", "1164571", "1177551", "1229221", "1229231", "1265811", "1265821", "1280491", "3488781", "3488771", "3488751", "3488761", "3488741", "1347941", "1347961", "1347971", "1347981", "1348101", "1348111", "1348121", "1348131", "1348141", "1348151", "1348161", "1348191", "1348201", "1348211", "1370101", "1370111", "3107001", "1475281", "1475291", "1475301", "1475271", "1475241", "1475251", "1475261", "1475311", "1475321", "1880471", "1880481", "1531721", "1531731", "1531761", "1531771", "1531781", "1531791", "1531801", "1531811", "1531821", "1531831", "1558861", "2944761", "1582181", "1601751", "2468781", "2468771", "1776961", "2459641", "2459651", "2459661", "2459671", "1824261", "1824331", "1824351", "1880511", "2457931", "2457901", "2457911", "2457921", "2457891", "1928631", "1928641", "1928651", "1928661", "1945411", "2012221", "2012231", "2105931", "2184331", "2184341", "2184351", "2202411", "2211571", "2226481", "2226491", "2226511", "2226521", "2226531", "2226561", "2226571", "2226581", "2226591", "2226601", "2226611", "2237101", "2237111", "2240091", "2241791", "2278921", "2305441", "2305461", "2305471", "2305481", "2314931", "2452271", "2366081", "2588931", "2613201", "2669741", "2669751", "2669761", "2669771", "2669781", "2669791", "2669801", "2669811", "2681211", "2698111", "2698131", "2724061", "2738291", "2738301", "2738311", "2750571", "2756371", "2796281", "2831181", "2831191", "2831201", "2831211", "2831221", "2831231", "2831241", "2831291", "2845721", "2831791", "2845751", "2845761", "2845771", "2875941", "2875951", "2875961", "2875971", "2875981", "2875991", "2876001", "2876011", "2876021", "2876031", "2876041", "2876051", "2876061", "2876071", "2876081", "2876091", "2876101", "2876111", "2876121", "2876131", "2876141", "2876151", "2876161", "2876171", "2902281", "2902291", "2902301", "2902311", "2902321", "2902331", "2902341", "2903101", "2905171", "2922911", "3489781", "2925151", "2925161", "2925171", "2925181", "2925191", "2925201", "2925211", "2925221", "2925231", "2925241", "2925251", "2925261", "2925271", "2925281", "2925291", "2925301", "2925411", "2932181", "2932141", "2932151", "2932161", "2932171", "2932191", "2932201", "2932211", "2932221", "2932231", "2932241", "2932251", "2932261", "2932271", "2932281", "2932291", "2932301", "2932311", "2932321", "2932331", "2943401", "2943411", "2943421", "2943431", "2943441", "2943451", "2943461", "2943471", "2961101", "2961661", "2969781", "2992001", "2996021", "3011261", "3011271", "3012721", "3018351", "3030521", "3054391", "3061861", "3061871", "3485271", "3071831", "3071881", "3071891", "3071901", "3071911", "3073051", "3073821", "3073831", "3073841", "3073851", "3073871", "3086011", "3097861", "3489921", "3489901", "3105081", "3107271", "3107281", "3109321", "3109331", "3109341", "3109351", "3109361", "3110601", "3111451", "3112871", "3125421", "3125431", "3135911", "3140901", "3140911", "3148661", "3148671", "3149091", "3150521", "3155731", "3155741", "3155751", "3162261", "3192901", "3198471", "3201471", "3204501", "3213821", "3215561", "3234881", "3235071"]}
100
+ def find_updates_since(time)
101
+ @_updated_results ||= {}
102
+ stamp = time.to_i # Get timestamp
103
+ result = @_updated_results[stamp] ||= self.class.get("/Updates.php?type=all&time=#{stamp}")['Items']
104
+ { :series => result['Series'].map(&:to_i), :episodes => result['Episode'].map(&:to_i), :time => result['Time'] }
105
+ end
106
+
107
+ protected
108
+
109
+ # Returns the given xml as a hash appending the api_key to the url
110
+ # tvdb.get_with_key("/some/url", :query => { :foo => "bar" })
111
+ def get_with_key(*args)
112
+ args[0] = "/#{@api_key}/" + args[0]
113
+ self.class.get(*args)
114
+ end
115
+
116
+ # Checks if the api key works by retrieving mirrors
117
+ def check_api_key!
118
+ self.mirror_urls
119
+ rescue
120
+ raise "Please check your TVDB API Key!"
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,79 @@
1
+ require 'Hashie' unless defined?(Hashie)
2
+
3
+ module Tvdbr
4
+ class DataSet < Hashie::Mash
5
+ attr_reader :parent
6
+
7
+ ## INSTANCE METHODS ##
8
+
9
+ # Tvdb::DataSet.new(self, { :foo => "bar" })
10
+ def initialize(parent, *args)
11
+ @parent = parent
12
+ args[0] = normalize_keys(args[0]) if args[0].is_a?(Hash)
13
+ super(*args)
14
+ end
15
+
16
+ # Outputs: <#Tvdb::Series actors="..." added=nil added_by=nil>
17
+ def inspect
18
+ ret = "<##{self.class.to_s}"
19
+ self.keys.sort.each do |key|
20
+ ret << " #{key}=#{self[key].inspect}"
21
+ end
22
+ ret << ">"
23
+ ret
24
+ end
25
+
26
+ ## CLASS METHODS ##
27
+
28
+ # Aliases the original propery to the new method name
29
+ # alias_property :old, :new
30
+ def self.alias_property(original, name)
31
+ define_method(name) { self.send(original) }
32
+ end
33
+
34
+ # Turns a property "a | b | c" => ['a', 'b', 'c']
35
+ # listify :lista, :listb
36
+ def self.listify(*attrs)
37
+ attrs.each do |a|
38
+ define_method(a) { self[a] ? self[a][1..-1].split("|").map(&:strip) : [] }
39
+ end
40
+ end
41
+
42
+ # Turns a property into a date object
43
+ # dateify :release_date
44
+ def self.dateify(*attrs)
45
+ attrs.each do |a|
46
+ define_method(a) { Time.parse(self[a]) if self[a] }
47
+ end
48
+ end
49
+
50
+ # Turns a relative image link to a full tvdb link url
51
+ # absolutize :file_name
52
+ def self.absolutize(*attrs)
53
+ attrs.each do |a|
54
+ define_method(a) { File.join("http://www.thetvdb.com/banners/", self[a]) if self[a] }
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ # Translates all keys to lowercase and to a symbol
61
+ # => [:foo => "bar", ...]
62
+ def normalize_keys(hash)
63
+ hash.inject({}) do |options, (key, value)|
64
+ options[(underscore(key) rescue key) || key] = value
65
+ options
66
+ end
67
+ end
68
+
69
+ def underscore(camel_cased_word)
70
+ word = camel_cased_word.to_s.dup
71
+ word.gsub!(/::/, '/')
72
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
73
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
74
+ word.tr!("-", "_")
75
+ word.downcase!
76
+ word
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,17 @@
1
+ module Tvdbr
2
+ # {:combined_episodenumber=>"14", :imdb_id=>nil, :episode_number=>"14", :absolute_number=>nil, :first_aired=>"2010-05-04",
3
+ # :dvd_episodenumber=>nil, :episode_name=>"The Candidate", :rating=>"7.9", :filename=>"episodes/73739/1685171.jpg", :director=>"Jack Bender",
4
+ # :seasonid=>"66871", :writer=>"|Elizabeth Sarnoff|Jim Galasso|", :dvd_chapter=>nil, :production_code=>nil, :combined_season=>"6", :season_number=>"6",
5
+ # :dvd_season=>nil, :language=>"en", :dvd_discid=>nil, :lastupdated=>"1277153526",
6
+ # :overview=>"...", :id=>"1685171", :ep_img_flag=>"2", :rating_count=>"187", :seriesid=>"73739", :guest_stars=>nil}
7
+ class Episode < DataSet
8
+ alias_property :episode_name, :name
9
+ alias_property :episode_number, :episode_num
10
+ alias_property :season_number, :season_num
11
+ alias_property :overview, :description
12
+ alias_property :first_aired, :original_air_date
13
+ dateify :first_aired
14
+ listify :writer
15
+ absolutize :filename
16
+ end
17
+ end
@@ -0,0 +1,36 @@
1
+ module Tvdbr
2
+ # { "ContentRating"=>"TV-MA", "Status"=>"Continuing", "Airs_Time"=>"9:00 PM", "FirstAired"=>"2006-10-01", "Runtime"=>"60",
3
+ # "banner"=>"graphical/79349-g7.jpg", "poster"=>"posters/79349-2.jpg", "id"=>"79349", "Genre"=>"|Action and Adventure|Drama|",
4
+ # "Network"=>"Showtime", "Overview"=>"...", "addedBy"=>nil, "lastupdated"=>"1295047217", "IMDB_ID"=>"tt0773262",
5
+ # "Language"=>"en", "SeriesName"=>"Dexter", "Rating"=>"9.3", "fanart"=>"fanart/original/79349-16.jpg",
6
+ # "Actors"=>"|Michael C. Hall|Julie Benz|", "Airs_DayOfWeek"=>"Sunday",
7
+ # "zap2it_id"=>"SH859795", "RatingCount"=>"678", "SeriesID"=>"62683" }
8
+ class Series < DataSet
9
+ alias_property :series_name, :title
10
+ alias_property :overview, :synopsis
11
+ alias_property :actors, :starring
12
+ alias_property :genre, :categories
13
+ alias_property :first_aired, :release_date
14
+ listify :genre, :actors
15
+ dateify :first_aired
16
+ absolutize :fanart, :poster, :banner
17
+
18
+ def episodes
19
+ episode_data = self.parent.find_series_by_id(self.id, :all => true)
20
+ return [] unless episode_data && episode_data['Episode']
21
+ episode_data['Episode'].map { |e| Episode.new(self, e) if e && e.is_a?(Hash) }.compact
22
+ end
23
+
24
+ # Returns true if the series matches the given actors
25
+ # actors = ['x', 'y', 'z']
26
+ # series.actor_match?(actors) => true
27
+ def actor_match?(actors)
28
+ expected_actors = actors.map { |a| a.downcase.strip.gsub(/[\.\-\s\']/, '') }
29
+ normalized_actors = self.actors.map { |a| a.downcase.strip.gsub(/[\.\-\s\']/, '') }
30
+ # puts "1: #{self.inspect} - #{self.title} - #{normalized_actors.inspect} - #{expected_actors.inspect}"
31
+ # puts "2: " + (normalized_actors & expected_actors).inspect
32
+ normalized_actors.is_a?(Array) && expected_actors.is_a?(Array) &&
33
+ (normalized_actors & expected_actors).size > 1
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ module Tvdbr
2
+ VERSION = "0.0.1"
3
+ end
data/lib/tvdbr.rb ADDED
@@ -0,0 +1,6 @@
1
+ module Tvdbr
2
+ autoload :Client, 'tvdbr/client'
3
+ autoload :DataSet, 'tvdbr/data_set'
4
+ autoload :Series, 'tvdbr/series'
5
+ autoload :Episode, 'tvdbr/episode'
6
+ end
data/spec/.gitkeep ADDED
File without changes
data/tvdbr.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "tvdbr/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "tvdbr"
7
+ s.version = Tvdbr::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Miso", "Nathan Esquenazi"]
10
+ s.email = ["nesquena@gmail.com"]
11
+ s.homepage = "https://github.com/bazaarlabs/tvdbr"
12
+ s.summary = %q{Use the TVDB API from Ruby}
13
+ s.description = %q{Utilize the TVDB API from Ruby to fetch shows, track updates to the tvdb and sync your media database}
14
+ s.rubyforge_project = "tvdbr"
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency "hashie"
21
+ s.add_dependency "httparty"
22
+ s.add_development_dependency "rake"
23
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tvdbr
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Miso
14
+ - Nathan Esquenazi
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2011-01-17 00:00:00 -08:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: hashie
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: httparty
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: rake
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ type: :development
63
+ version_requirements: *id003
64
+ description: Utilize the TVDB API from Ruby to fetch shows, track updates to the tvdb and sync your media database
65
+ email:
66
+ - nesquena@gmail.com
67
+ executables: []
68
+
69
+ extensions: []
70
+
71
+ extra_rdoc_files: []
72
+
73
+ files:
74
+ - .gitignore
75
+ - Gemfile
76
+ - Gemfile.lock
77
+ - README
78
+ - Rakefile
79
+ - examples/demo.rb
80
+ - lib/tvdbr.rb
81
+ - lib/tvdbr/client.rb
82
+ - lib/tvdbr/data_set.rb
83
+ - lib/tvdbr/episode.rb
84
+ - lib/tvdbr/series.rb
85
+ - lib/tvdbr/version.rb
86
+ - spec/.gitkeep
87
+ - tvdbr.gemspec
88
+ has_rdoc: true
89
+ homepage: https://github.com/bazaarlabs/tvdbr
90
+ licenses: []
91
+
92
+ post_install_message:
93
+ rdoc_options: []
94
+
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ hash: 3
103
+ segments:
104
+ - 0
105
+ version: "0"
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ hash: 3
112
+ segments:
113
+ - 0
114
+ version: "0"
115
+ requirements: []
116
+
117
+ rubyforge_project: tvdbr
118
+ rubygems_version: 1.3.7
119
+ signing_key:
120
+ specification_version: 3
121
+ summary: Use the TVDB API from Ruby
122
+ test_files:
123
+ - spec/.gitkeep