tivohmo 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c1dd209625032c02880d0be351f2455545e10bba
4
- data.tar.gz: 37f59ce8d6b891f3205c92a1e2db38b4f4b09fca
3
+ metadata.gz: d174442bc2cdc54f0c321af10235ca9b7b0cd5e6
4
+ data.tar.gz: 9879d1b6792705f0838f2f9a12c7fd00f4b1bc1e
5
5
  SHA512:
6
- metadata.gz: 6594266dc18d59842e0fa8966507094821322fb8325451b01c6d7f7d607a7aab6503ce567fd976a3b579eb663aeaea6bab9990cd44d22992de4445896bc353c9
7
- data.tar.gz: 5b1757fa7d5cbd2d4150a1ce93daf2b4c955ecf365264ebcb9bc6176efcc7ed239762541f1e0c4057eb5e7bd1e6dd8f9bb261c3613bdeff5f33abe391eba289f
6
+ metadata.gz: 82fb8a7e0deb9d7d62be6b8809264dabaf1c23d776d53fa7ea90a0094a99ad354e97ef676663c863b6620ec5a13820b88a8449af865e036f0d7a0e430e4fcd8f
7
+ data.tar.gz: fdcae9f54909c5122e99fe76528f3690f58f67cbc0853c535b51100faa3a4ff5eb6caf2c3688a84c968ee581e44cc14899d206252351a3764689ff5b88b7c0f7
@@ -25,7 +25,12 @@ module TivoHMO
25
25
  def children
26
26
  synchronize do
27
27
  if super.blank?
28
- Array(server.library.sections).each do |section|
28
+ sections = Array(server.library.sections)
29
+ # Sort by title descending so that creation times are
30
+ # correct for tivo sort of newest first (Time.now for
31
+ # created_at in Section)
32
+ sections = sections.sort_by(&:title).reverse
33
+ sections.each do |section|
29
34
  add_child(Section.new(section))
30
35
  end
31
36
  end
@@ -26,7 +26,7 @@ module TivoHMO
26
26
  end
27
27
 
28
28
  self.modified_at = Time.at(delegate.updated_at.to_i)
29
- self.created_at = Time.at(delegate.updated_at.to_i)
29
+ self.created_at = Time.now
30
30
  end
31
31
 
32
32
  def children
@@ -16,7 +16,8 @@ module TivoHMO
16
16
 
17
17
  self.title = delegate.title
18
18
  self.modified_at = Time.at(delegate.updated_at.to_i)
19
- self.created_at = Time.at(delegate.added_at.to_i)
19
+ self.created_at = Time.parse(delegate.originally_available_at) rescue nil
20
+ self.created_at ||= Time.at(delegate.added_at.to_i)
20
21
  end
21
22
 
22
23
  def metadata
@@ -41,6 +42,10 @@ module TivoHMO
41
42
  # group tv shows under same name if we can extract a seriesId
42
43
  guid = delegate.guid
43
44
  if guid =~ /thetvdb:\/\/(\d+)/
45
+ # TODO: figure out how to get zap2it series IDs into plex
46
+ # If we had zap2it ids in plex metadata and extracted them
47
+ # here, tivo would show a relevant thumbnail image for the
48
+ # series in the My Shows UI.
44
49
  md.series_id = "SH#{$1}"
45
50
  end
46
51
 
@@ -16,7 +16,8 @@ module TivoHMO
16
16
 
17
17
  self.title = delegate.title
18
18
  self.modified_at = Time.at(delegate.updated_at.to_i)
19
- self.created_at = Time.at(delegate.added_at.to_i)
19
+ self.created_at = Time.parse(delegate.originally_available_at) rescue nil
20
+ self.created_at ||= Time.at(delegate.added_at.to_i)
20
21
  end
21
22
 
22
23
  def metadata
@@ -20,7 +20,7 @@ module TivoHMO
20
20
  self.category_qualifier = category_qualifier
21
21
  self.title = category_type.to_s.titleize
22
22
  self.modified_at = Time.at(delegate.updated_at.to_i)
23
- self.created_at = Time.at(delegate.updated_at.to_i)
23
+ self.created_at = Time.now
24
24
  end
25
25
 
26
26
  def children
@@ -35,7 +35,12 @@ module TivoHMO
35
35
  end
36
36
 
37
37
  if super.blank?
38
- Array(delegate.send(category_qualifier)).each do |category_value|
38
+ qualified = Array(delegate.send(category_qualifier))
39
+ # Sort by title descending so that creation times are
40
+ # correct for tivo sort of newest first (Time.now for
41
+ # created_at in Category)
42
+ qualified = qualified.sort_by{|c| c[:title] }.reverse
43
+ qualified.each do |category_value|
39
44
  add_child(Category.new(delegate, category_type, category_value))
40
45
  end
41
46
  end
@@ -17,24 +17,28 @@ module TivoHMO
17
17
 
18
18
  self.title = delegate.title
19
19
  self.modified_at = Time.at(delegate.updated_at.to_i)
20
- self.created_at = Time.at(delegate.updated_at.to_i)
20
+ self.created_at = Time.now
21
21
  end
22
22
 
23
23
  def children
24
24
  synchronize do
25
25
  if super.blank?
26
- add_child(Category.new(delegate, :recently_added))
26
+ # Tivo time sorting is reverse chronological (newest first), so
27
+ # order it here in reverse order so the creation time cause the
28
+ # right sorting ("all" is newest and comes first)
29
+ add_child(QualifiedCategory.new(delegate, :by_collection, :collections))
30
+ add_child(QualifiedCategory.new(delegate, :by_content_rating, :content_ratings))
31
+ add_child(QualifiedCategory.new(delegate, :by_folder, :folders))
32
+ add_child(QualifiedCategory.new(delegate, :by_genre, :genres))
33
+ add_child(QualifiedCategory.new(delegate, :by_year, :years))
34
+ add_child(QualifiedCategory.new(delegate, :by_first_character, :first_characters))
35
+
27
36
  #add_child(Category.new(delegate, :unwatched))
28
- add_child(Category.new(delegate, :newest))
29
37
  add_child(Category.new(delegate, :on_deck))
38
+ add_child(Category.new(delegate, :newest))
30
39
  add_child(Category.new(delegate, :recently_viewed))
40
+ add_child(Category.new(delegate, :recently_added))
31
41
  add_child(Category.new(delegate, :all))
32
- add_child(QualifiedCategory.new(delegate, :by_genre, :genres))
33
- add_child(QualifiedCategory.new(delegate, :by_year, :years))
34
- add_child(QualifiedCategory.new(delegate, :by_first_character, :first_characters))
35
- add_child(QualifiedCategory.new(delegate, :by_collection, :collections))
36
- add_child(QualifiedCategory.new(delegate, :by_folder, :folders))
37
- add_child(QualifiedCategory.new(delegate, :by_content_rating, :content_ratings))
38
42
  end
39
43
  end
40
44
 
@@ -7,7 +7,7 @@ module TivoHMO
7
7
  class Beacon
8
8
  include GemLogger::LoggerSupport
9
9
 
10
- def initialize(service_port, limit: -1, interval: 60)
10
+ def initialize(service_port, limit: -1, interval: 10)
11
11
  @interval = interval
12
12
  @limit = limit
13
13
  @uid = SecureRandom.uuid
@@ -23,7 +23,11 @@ module TivoHMO
23
23
  @running = true
24
24
  @broadcast_thread = Thread.new do
25
25
  while @running
26
- broadcast
26
+ begin
27
+ broadcast
28
+ rescue => e
29
+ logger.log_exception(e, "Ignoring exception in beacon thread")
30
+ end
27
31
  sleep(@interval)
28
32
  @limit = @limit - 1
29
33
  break if @limit == 0
@@ -61,6 +61,19 @@ module TivoHMO
61
61
  headers['TiVo_TCD_ID']
62
62
  end
63
63
 
64
+ def select_all_items(children)
65
+ just_items = []
66
+ all = children.dup
67
+ all.each do |child|
68
+ if child.is_a?(TivoHMO::API::Container)
69
+ all.concat(child.children)
70
+ else
71
+ just_items << child
72
+ end
73
+ end
74
+ children = just_items.uniq {|node| node.identifier }
75
+ end
76
+
64
77
  def sort(items, sort_order)
65
78
  sort_order = sort_order.split(/\s*,\s*/)
66
79
 
@@ -181,7 +194,8 @@ module TivoHMO
181
194
  item_count = (params['ItemCount'] || 8).to_i
182
195
 
183
196
  # Yes or No, default no
184
- recurse = (params['Recurse'] == 'Yes')
197
+ # TODO: fix this when tivo side is fixed or config mechanism added to globally disable recurse
198
+ recurse = false #(params['Recurse'] == 'Yes')
185
199
 
186
200
  # csv of Type, Title, CreationDate, LastChangeDate, Random
187
201
  # reverse with preceding !
@@ -216,6 +230,9 @@ module TivoHMO
216
230
  halt 404, "No container found for #{container_path}" unless container
217
231
 
218
232
  children = container.children
233
+
234
+ children = select_all_items(children) if recurse
235
+
219
236
  children = sort(children, sort_order) if sort_order
220
237
 
221
238
  if anchor_item
@@ -1,3 +1,3 @@
1
1
  module TivoHMO
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
@@ -8,15 +8,19 @@ describe TivoHMO::Adapters::Plex::Category do
8
8
  describe "#initialize" do
9
9
 
10
10
  it "should instantiate" do
11
- category = described_class.new(plex_delegate, :newest)
12
- expect(category).to be_a described_class
13
- expect(category).to be_a TivoHMO::API::Container
14
- expect(category.category_type).to eq(:newest)
15
- expect(category.category_value).to be_nil
16
- expect(category.title).to eq('Newest')
17
- expect(category.identifier).to eq(plex_delegate.key)
18
- expect(category.modified_at).to eq(Time.at(plex_delegate.updated_at))
19
- expect(category.created_at).to eq(Time.at(plex_delegate.added_at))
11
+ now = Time.now
12
+ Timecop.freeze(now) do
13
+ category = described_class.new(plex_delegate, :newest)
14
+ expect(category).to be_a described_class
15
+ expect(category).to be_a TivoHMO::API::Container
16
+ expect(category.category_type).to eq(:newest)
17
+ expect(category.category_value).to be_nil
18
+ expect(category.title).to eq('Newest')
19
+ expect(category.identifier).to eq(plex_delegate.key)
20
+ expect(category.modified_at).to eq(Time.at(plex_delegate.updated_at))
21
+ expect(category.created_at).to eq(now)
22
+ end
23
+
20
24
  end
21
25
 
22
26
  it "should use_category_value for title if present" do
@@ -32,7 +36,7 @@ describe TivoHMO::Adapters::Plex::Category do
32
36
  describe "#children" do
33
37
 
34
38
  it "should memoize" do
35
- listing = [plex_stub(::Plex::Movie)]
39
+ listing = [plex_stub(::Plex::Movie, originally_available_at: "2013-01-02")]
36
40
  allow(plex_delegate).to receive(:newest).and_return(listing)
37
41
  section = described_class.new(plex_delegate, :newest)
38
42
  expect(section.children.object_id).to eq(section.children.object_id)
@@ -40,8 +44,8 @@ describe TivoHMO::Adapters::Plex::Category do
40
44
 
41
45
  it "should have children" do
42
46
  listing = [
43
- plex_stub(::Plex::Movie),
44
- plex_stub(::Plex::Episode),
47
+ plex_stub(::Plex::Movie, originally_available_at: "2013-01-02"),
48
+ plex_stub(::Plex::Episode, originally_available_at: "2013-01-02"),
45
49
  plex_stub(::Plex::Show)
46
50
  ]
47
51
  allow(plex_delegate).to receive(:newest).and_return(listing)
@@ -51,8 +55,8 @@ describe TivoHMO::Adapters::Plex::Category do
51
55
 
52
56
  it "should use category_value for children" do
53
57
  listing = [
54
- plex_stub(::Plex::Movie),
55
- plex_stub(::Plex::Episode),
58
+ plex_stub(::Plex::Movie, originally_available_at: "2013-01-02"),
59
+ plex_stub(::Plex::Episode, originally_available_at: "2013-01-02"),
56
60
  plex_stub(::Plex::Show)
57
61
  ]
58
62
  cval = {title: 'Title', key: 'key'}
@@ -20,7 +20,7 @@ describe TivoHMO::Adapters::Plex::Episode do
20
20
  expect(episode.title).to eq(plex_delegate.title)
21
21
  expect(episode.identifier).to eq(plex_delegate.key)
22
22
  expect(episode.modified_at).to eq(Time.at(plex_delegate.updated_at))
23
- expect(episode.created_at).to eq(Time.at(plex_delegate.added_at))
23
+ expect(episode.created_at).to eq(Time.parse(plex_delegate.originally_available_at))
24
24
  end
25
25
 
26
26
  end
@@ -16,7 +16,7 @@ describe TivoHMO::Adapters::Plex::Movie do
16
16
  expect(movie.title).to eq(plex_delegate.title)
17
17
  expect(movie.identifier).to eq(plex_delegate.key)
18
18
  expect(movie.modified_at).to eq(Time.at(plex_delegate.updated_at))
19
- expect(movie.created_at).to eq(Time.at(plex_delegate.added_at))
19
+ expect(movie.created_at).to eq(Time.parse(plex_delegate.originally_available_at))
20
20
  end
21
21
 
22
22
  end
@@ -9,15 +9,18 @@ describe TivoHMO::Adapters::Plex::QualifiedCategory do
9
9
  describe "#initialize" do
10
10
 
11
11
  it "should instantiate" do
12
- qcat = described_class.new(plex_delegate, :by_year, '2000')
13
- expect(qcat).to be_a described_class
14
- expect(qcat).to be_a TivoHMO::API::Container
15
- expect(qcat.title).to eq("By Year")
16
- expect(qcat.category_qualifier).to eq('2000')
17
- expect(qcat.title).to eq("By Year")
18
- expect(qcat.identifier).to eq(plex_delegate.key)
19
- expect(qcat.modified_at).to eq(Time.at(plex_delegate.updated_at))
20
- expect(qcat.created_at).to eq(Time.at(plex_delegate.added_at))
12
+ now = Time.now
13
+ Timecop.freeze(now) do
14
+ qcat = described_class.new(plex_delegate, :by_year, '2000')
15
+ expect(qcat).to be_a described_class
16
+ expect(qcat).to be_a TivoHMO::API::Container
17
+ expect(qcat.title).to eq("By Year")
18
+ expect(qcat.category_qualifier).to eq('2000')
19
+ expect(qcat.title).to eq("By Year")
20
+ expect(qcat.identifier).to eq(plex_delegate.key)
21
+ expect(qcat.modified_at).to eq(Time.at(plex_delegate.updated_at))
22
+ expect(qcat.created_at).to eq(now)
23
+ end
21
24
  end
22
25
 
23
26
  end
@@ -43,7 +46,9 @@ describe TivoHMO::Adapters::Plex::QualifiedCategory do
43
46
  expect(section.children.size).to eq(2)
44
47
  expect(section.children[0]).to be_instance_of(TivoHMO::Adapters::Plex::Category)
45
48
  expect(section.children[0].category_type).to be(:by_year)
46
- expect(section.children[0].category_value).to eq(listing[0])
49
+ # reverse order due to sorting by title reversed to work with tivo newest first sorting
50
+ expect(section.children[0].category_value).to eq(listing[1])
51
+ expect(section.children[1].category_value).to eq(listing[0])
47
52
  end
48
53
 
49
54
  end
@@ -8,13 +8,16 @@ describe TivoHMO::Adapters::Plex::Section do
8
8
  describe "#initialize" do
9
9
 
10
10
  it "should instantiate" do
11
- section = described_class.new(plex_delegate)
12
- expect(section).to be_a described_class
13
- expect(section).to be_a TivoHMO::API::Container
14
- expect(section.title).to eq(plex_delegate.title)
15
- expect(section.identifier).to eq(plex_delegate.key)
16
- expect(section.modified_at).to eq(Time.at(plex_delegate.updated_at))
17
- expect(section.created_at).to eq(Time.at(plex_delegate.added_at))
11
+ now = Time.now
12
+ Timecop.freeze(now) do
13
+ section = described_class.new(plex_delegate)
14
+ expect(section).to be_a described_class
15
+ expect(section).to be_a TivoHMO::API::Container
16
+ expect(section.title).to eq(plex_delegate.title)
17
+ expect(section.identifier).to eq(plex_delegate.key)
18
+ expect(section.modified_at).to eq(Time.at(plex_delegate.updated_at))
19
+ expect(section.created_at).to eq(now)
20
+ end
18
21
  end
19
22
 
20
23
  end
@@ -30,7 +33,7 @@ describe TivoHMO::Adapters::Plex::Section do
30
33
  section = described_class.new(plex_delegate)
31
34
  expect(section.children.size).to eq(11)
32
35
  classes = [TivoHMO::Adapters::Plex::Category, TivoHMO::Adapters::Plex::QualifiedCategory]
33
- expect(section.children.collect(&:class).uniq).to eq(classes)
36
+ expect(section.children.collect(&:class).uniq.sort_by(&:name)).to eq(classes.sort_by(&:name))
34
37
  end
35
38
 
36
39
  end
data/spec/beacon_spec.rb CHANGED
@@ -9,7 +9,7 @@ describe TivoHMO::Beacon do
9
9
  beacon = described_class.new(1234)
10
10
  expect(beacon).to be_a described_class
11
11
  expect(beacon.instance_variable_get(:@limit)).to eq(-1)
12
- expect(beacon.instance_variable_get(:@interval)).to eq(60)
12
+ expect(beacon.instance_variable_get(:@interval)).to eq(10)
13
13
  expect(beacon.instance_variable_get(:@services)).to eq(['TiVoMediaServer:1234/http'])
14
14
  end
15
15
 
data/spec/server_spec.rb CHANGED
@@ -288,6 +288,33 @@ describe TivoHMO::Server do
288
288
 
289
289
  end
290
290
 
291
+ describe "recursing" do
292
+
293
+ before(:each) do
294
+ other_container = container.add_child(TestAPI::Container.new("c2"))
295
+ other_container.add_child(TestAPI::Item.new("i2")) # dupe child
296
+ other_container.add_child(TestAPI::Item.new("i98")) # unique child
297
+
298
+ third_container = other_container.add_child(TestAPI::Container.new("c3"))
299
+ other_container.add_child(TestAPI::Item.new("i99")) # unique child
300
+ other_container.add_child(TestAPI::Item.new("i3")) # dupe child
301
+
302
+ 3.times do |i|
303
+ container.add_child(TestAPI::Item.new("i#{i + 2}"))
304
+ end
305
+ end
306
+
307
+ it "recurses all items uniquely" do
308
+ skip "recurse disabled because tivo forces it on initially (no memory)"
309
+ get "/TiVoConnect?Command=QueryContainer&Container=/a1/c1&Recurse=Yes"
310
+ expect(last_response.status).to eq(200)
311
+ doc = Nokogiri::XML(last_response.body)
312
+ child_titles = doc.xpath("/TiVoContainer/Item/Details/Title").collect(&:content)
313
+ expect(child_titles).to eq(["i1", "i2", "i3", "i4", "i98", "i99"])
314
+ end
315
+
316
+ end
317
+
291
318
  describe "sorting" do
292
319
 
293
320
  before(:each) do
data/spec/spec_helper.rb CHANGED
@@ -3,6 +3,8 @@ require 'rspec'
3
3
  RSpec.configure do |config|
4
4
  end
5
5
 
6
+ require 'timecop'
7
+
6
8
  require 'coveralls'
7
9
  Coveralls.wear!
8
10
 
data/tivohmo.gemspec CHANGED
@@ -26,6 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency "rspec"
27
27
  spec.add_development_dependency "rack-test"
28
28
  spec.add_development_dependency "nokogiri"
29
+ spec.add_development_dependency "timecop"
29
30
 
30
31
  # core dependencies
31
32
  spec.add_dependency "activesupport"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tivohmo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Conway
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-23 00:00:00.000000000 Z
11
+ date: 2014-11-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: timecop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: activesupport
127
141
  requirement: !ruby/object:Gem::Requirement