tivohmo 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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