tivohmo 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG +30 -0
  4. data/Gemfile +2 -0
  5. data/README.md +4 -6
  6. data/TODO +1 -0
  7. data/contrib/tivohmo.conf +2 -2
  8. data/contrib/tivohmo.plist +1 -1
  9. data/contrib/tivohmo.yml +60 -0
  10. data/lib/tivohmo/adapters/filesystem/file_item.rb +2 -3
  11. data/lib/tivohmo/adapters/plex/category.rb +87 -6
  12. data/lib/tivohmo/adapters/plex/episode.rb +30 -11
  13. data/lib/tivohmo/adapters/plex/group.rb +20 -0
  14. data/lib/tivohmo/adapters/plex/movie.rb +15 -3
  15. data/lib/tivohmo/adapters/plex/qualified_category.rb +14 -3
  16. data/lib/tivohmo/adapters/plex/season.rb +2 -2
  17. data/lib/tivohmo/adapters/plex/section.rb +5 -5
  18. data/lib/tivohmo/adapters/plex/transcoder.rb +5 -1
  19. data/lib/tivohmo/adapters/plex.rb +1 -0
  20. data/lib/tivohmo/adapters/settings/application.rb +37 -0
  21. data/lib/tivohmo/adapters/settings/display_item.rb +35 -0
  22. data/lib/tivohmo/adapters/settings/key_container.rb +35 -0
  23. data/lib/tivohmo/adapters/settings/metadata.rb +26 -0
  24. data/lib/tivohmo/adapters/settings/reset_defaults_item.rb +39 -0
  25. data/lib/tivohmo/adapters/settings/set_value_item.rb +38 -0
  26. data/lib/tivohmo/adapters/settings/transcoder.rb +23 -0
  27. data/lib/tivohmo/adapters/settings.rb +7 -0
  28. data/lib/tivohmo/adapters/streamio/transcoder.rb +39 -1
  29. data/lib/tivohmo/api/container.rb +5 -1
  30. data/lib/tivohmo/api/item.rb +2 -0
  31. data/lib/tivohmo/api/subtitle.rb +13 -0
  32. data/lib/tivohmo/api/transcoder.rb +1 -3
  33. data/lib/tivohmo/api.rb +1 -0
  34. data/lib/tivohmo/beacon.rb +3 -3
  35. data/lib/tivohmo/cli.rb +175 -48
  36. data/lib/tivohmo/config.rb +157 -0
  37. data/lib/tivohmo/server/views/_container.builder +1 -1
  38. data/lib/tivohmo/server.rb +6 -3
  39. data/lib/tivohmo/version.rb +1 -1
  40. data/lib/tivohmo.rb +1 -0
  41. data/spec/adapters/filesystem/file_item_spec.rb +1 -1
  42. data/spec/adapters/plex/application_spec.rb +10 -1
  43. data/spec/adapters/plex/category_spec.rb +93 -20
  44. data/spec/adapters/plex/episode_spec.rb +34 -15
  45. data/spec/adapters/plex/metadata_spec.rb +5 -7
  46. data/spec/adapters/plex/movie_spec.rb +10 -7
  47. data/spec/adapters/plex/qualified_category_spec.rb +17 -17
  48. data/spec/adapters/plex/season_spec.rb +23 -4
  49. data/spec/adapters/plex/section_spec.rb +4 -4
  50. data/spec/adapters/plex/show_spec.rb +19 -4
  51. data/spec/adapters/plex/transcoder_spec.rb +2 -8
  52. data/spec/adapters/settings/application_spec.rb +25 -0
  53. data/spec/adapters/settings/display_item_spec.rb +29 -0
  54. data/spec/adapters/settings/key_container_spec.rb +33 -0
  55. data/spec/adapters/settings/metadata_spec.rb +33 -0
  56. data/spec/adapters/settings/reset_defaults_item_spec.rb +54 -0
  57. data/spec/adapters/settings/set_value_item_spec.rb +54 -0
  58. data/spec/api/container_spec.rb +12 -0
  59. data/spec/api/item_spec.rb +2 -0
  60. data/spec/api/transcoder_spec.rb +0 -1
  61. data/spec/beacon_spec.rb +3 -1
  62. data/spec/cli_spec.rb +57 -19
  63. data/spec/config_spec.rb +224 -0
  64. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Application/_children/should_get_children.yml +61 -0
  65. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_allow_disabling_subtitles.yml +424 -0
  66. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_display_non-zero_child_count_once_children_fetched.yml +653 -0
  67. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_have_children.yml +599 -0
  68. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_have_children_with_embedded_subtitles.yml +595 -0
  69. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_have_children_with_subtitles.yml +482 -0
  70. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_memoize.yml +478 -0
  71. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_refresh_children_when_config_changes.yml +1245 -0
  72. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_use_category_value_for_children.yml +395 -0
  73. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_initialize/should_instantiate.yml +61 -0
  74. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_initialize/should_set_presorted_if_present.yml +61 -0
  75. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_initialize/should_use_category_value_for_title_if_present.yml +61 -0
  76. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Episode/_initialize/should_instantiate.yml +444 -0
  77. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Episode/_metadata/should_allow_disabling_series_id_in_metadata.yml +444 -0
  78. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Episode/_metadata/should_populate_metadata.yml +579 -0
  79. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Metadata/_initialize/should_instantiate.yml +296 -0
  80. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Movie/_initialize/should_instantiate.yml +296 -0
  81. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Movie/_metadata/should_populate_metadata.yml +296 -0
  82. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_QualifiedCategory/_children/should_display_non-zero_child_count_once_children_fetched.yml +220 -0
  83. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_QualifiedCategory/_children/should_have_children.yml +393 -0
  84. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_QualifiedCategory/_children/should_memoize.yml +219 -0
  85. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_QualifiedCategory/_initialize/should_instantiate.yml +61 -0
  86. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Season/_children/should_have_children.yml +444 -0
  87. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Season/_children/should_memoize.yml +444 -0
  88. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Season/_initialize/should_instantiate.yml +250 -0
  89. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Section/_children/should_have_category_children.yml +61 -0
  90. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Section/_children/should_memoize.yml +61 -0
  91. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Section/_initialize/should_instantiate.yml +61 -0
  92. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Show/_children/should_have_children.yml +250 -0
  93. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Show/_children/should_memoize.yml +250 -0
  94. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Show/_initialize/should_instantiate.yml +166 -0
  95. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Transcoder/_initialize/should_instantiate.yml +296 -0
  96. data/spec/server_spec.rb +31 -2
  97. data/spec/spec_helper.rb +24 -36
  98. data/tivohmo.gemspec +2 -2
  99. metadata +109 -3
@@ -0,0 +1,157 @@
1
+ require 'hashie'
2
+
3
+ module TivoHMO
4
+
5
+ class Config
6
+ include GemLogger::LoggerSupport
7
+ include Singleton
8
+
9
+ def initialize
10
+ super
11
+ @primary_data = Data.new
12
+ @secondary_data = Data.new
13
+ end
14
+
15
+
16
+ def setup(primary_filename, secondary_filename=nil)
17
+ @primary_file = primary_filename
18
+ @secondary_file = secondary_filename
19
+
20
+ @primary_data = Data.new
21
+ @secondary_data = Data.new
22
+
23
+ if File.exist?(@primary_file.to_s)
24
+ logger.info "Loading primary config from: '#{@primary_file}'"
25
+ @primary_data = Data.load(@primary_file)
26
+ else
27
+ logger.info "No primary config at file: '#{@primary_file}'"
28
+ end
29
+
30
+ # get secondary config from primary if present and not set explictly
31
+ secondary = get(:settings)
32
+ @secondary_file ||= File.expand_path(secondary) if secondary
33
+
34
+ if File.exist?(@secondary_file.to_s)
35
+ logger.info "Loading secondary config from: '#{@secondary_file}'"
36
+ @secondary_data = Data.load(@secondary_file)
37
+ else
38
+ logger.info "No secondary config at file: '#{@secondary_file}'"
39
+ end
40
+ end
41
+
42
+ def reset
43
+ @primary_file = @secondary_file = nil
44
+ @primary_data = @secondary_data = nil
45
+ @known_config = nil
46
+ end
47
+
48
+ def known_config
49
+ @known_config ||= {}
50
+ end
51
+
52
+ def get(scoped_key)
53
+ scoped_key = Array(scoped_key)
54
+ result = nil
55
+
56
+ key = scoped_key.pop
57
+ path = scoped_key
58
+ (0..path.size).to_a.reverse.each do |i|
59
+ partial = path[0, i] << key
60
+
61
+ begin
62
+ result = @secondary_data.deep_fetch(*partial)
63
+ rescue Data::UndefinedPathError
64
+ begin
65
+ result = @primary_data.deep_fetch(*partial)
66
+ rescue Data::UndefinedPathError
67
+ end
68
+ end
69
+
70
+ break if ! result.nil?
71
+ end
72
+
73
+ if result.nil?
74
+ registered = known_config[key]
75
+ result = registered[:default_value] if registered
76
+ end
77
+
78
+ result
79
+ end
80
+
81
+ def set(scoped_key, value, persist=true)
82
+ scoped_key = Array(scoped_key)
83
+ key = scoped_key.pop
84
+
85
+ val_hash = {key => value}
86
+ scoped_key.reverse.each do |k|
87
+ val_hash = {k => val_hash}
88
+ end
89
+
90
+ @secondary_data = @secondary_data.deep_merge(val_hash)
91
+ File.write(@secondary_file, YAML.dump(@secondary_data)) if persist && @secondary_file
92
+
93
+ registered = known_config[key]
94
+ if registered && registered[:on_change]
95
+ registered[:on_change].call
96
+ end
97
+ end
98
+
99
+ class Data < ::Hash
100
+ include Hashie::Extensions::IndifferentAccess
101
+ include Hashie::Extensions::DeepFetch
102
+
103
+ def self.load(filename)
104
+ h = Hashie::Extensions::Parsers::YamlErbParser.perform(filename)
105
+ new.replace(h)
106
+ end
107
+ end
108
+
109
+ module Mixin
110
+ extend ActiveSupport::Concern
111
+
112
+ included do
113
+ delegate :config_register,
114
+ :config_get,
115
+ :config_set,
116
+ :to => "self.class"
117
+
118
+ end
119
+
120
+ module ClassMethods
121
+
122
+ def config_register(key, default_value, description, &on_change_block)
123
+ raise ArgumentError, "Config '#{key}' already registered" if Config.instance.known_config[key]
124
+
125
+ Config.instance.known_config[key] = {
126
+ default_value: default_value,
127
+ description: description,
128
+ source_path: config_path,
129
+ on_change: on_change_block
130
+ }
131
+ end
132
+
133
+ def config_get(key)
134
+ scoped_key = config_path << key
135
+ result = Config.instance.get(scoped_key)
136
+ result
137
+ end
138
+
139
+ def config_set(key, value)
140
+ Config.instance.set(key, value)
141
+ end
142
+
143
+ private
144
+
145
+ def config_path
146
+ path = self.name.underscore
147
+ path = path.sub(/.*tivo_hmo\//, '')
148
+ pieces = path.split('/')
149
+ pieces
150
+ end
151
+
152
+ end
153
+ end
154
+
155
+ end
156
+
157
+ end
@@ -5,7 +5,7 @@ xml.Item do
5
5
  xml.ContentType container.content_type
6
6
  xml.SourceFormat container.source_format
7
7
  xml.UniqueId format_uuid(container.uuid)
8
- xml.TotalItems container.children.size
8
+ xml.TotalItems container.child_count
9
9
  xml.LastCaptureDate format_date(container.created_at) if container.created_at
10
10
  end
11
11
 
@@ -12,6 +12,10 @@ module TivoHMO
12
12
  # tivo format
13
13
  class Server < Sinatra::Base
14
14
  include GemLogger::LoggerSupport
15
+ include TivoHMO::Config::Mixin
16
+
17
+ config_register(:force_grouping, true,
18
+ "Force groups/folders regardless of parameters supplied by the tivo request")
15
19
 
16
20
  disable :logging
17
21
  set :root, File.expand_path("../server", __FILE__)
@@ -211,8 +215,7 @@ module TivoHMO
211
215
  item_count = (params['ItemCount'] || 8).to_i
212
216
 
213
217
  # Yes or No, default no
214
- # TODO: fix this when tivo side is fixed or config mechanism added to globally disable recurse
215
- recurse = false #(params['Recurse'] == 'Yes')
218
+ recurse = config_get(:force_grouping) ? false : (params['Recurse'] == 'Yes')
216
219
 
217
220
  # csv of Type, Title, CreationDate, LastChangeDate, Random
218
221
  # reverse with preceding !
@@ -250,7 +253,7 @@ module TivoHMO
250
253
 
251
254
  children = select_all_items(children) if recurse
252
255
 
253
- children = sort(children, sort_order) if sort_order
256
+ children = sort(children, sort_order) if sort_order && ! container.presorted
254
257
 
255
258
  if anchor_item
256
259
  anchor = server.find(anchor_item)
@@ -1,3 +1,3 @@
1
1
  module TivoHMO
2
- VERSION = "0.2.3"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/tivohmo.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'gem_logger'
2
2
  require "tivohmo/version"
3
3
  require "tivohmo/api"
4
+ require "tivohmo/config"
4
5
  require "tivohmo/server"
5
6
  require "tivohmo/beacon"
@@ -20,7 +20,7 @@ describe TivoHMO::Adapters::Filesystem::FileItem do
20
20
  file = __FILE__
21
21
  subject = described_class.new(file)
22
22
  expect(subject).to be_a described_class
23
- expect(subject.full_path).to eq File.expand_path(file)
23
+ expect(subject.file).to eq File.expand_path(file)
24
24
  expect(subject.title).to eq File.basename(file)
25
25
  expect(subject.modified_at).to_not be_nil
26
26
  expect(subject.created_at).to_not be_nil
@@ -1,7 +1,7 @@
1
1
  require_relative "../../spec_helper"
2
2
  require 'tivohmo/adapters/plex'
3
3
 
4
- describe TivoHMO::Adapters::Plex::Application do
4
+ describe TivoHMO::Adapters::Plex::Application, :vcr do
5
5
 
6
6
 
7
7
  describe "#initialize" do
@@ -17,4 +17,13 @@ describe TivoHMO::Adapters::Plex::Application do
17
17
 
18
18
  end
19
19
 
20
+ describe "#children" do
21
+
22
+ it "should get children" do
23
+ app = described_class.new('localhost')
24
+ expect(app.children).to_not be_empty
25
+ end
26
+
27
+ end
28
+
20
29
  end
@@ -1,9 +1,9 @@
1
1
  require_relative "../../spec_helper"
2
2
  require 'tivohmo/adapters/plex'
3
3
 
4
- describe TivoHMO::Adapters::Plex::Category do
4
+ describe TivoHMO::Adapters::Plex::Category, :vcr do
5
5
 
6
- let(:plex_delegate) { plex_stub(::Plex::Section) }
6
+ let(:plex_delegate) { plex_movie_section }
7
7
 
8
8
  describe "#initialize" do
9
9
 
@@ -15,9 +15,10 @@ describe TivoHMO::Adapters::Plex::Category do
15
15
  expect(category).to be_a TivoHMO::API::Container
16
16
  expect(category.category_type).to eq(:newest)
17
17
  expect(category.category_value).to be_nil
18
+ expect(category.presorted).to eq(false)
18
19
  expect(category.title).to eq('Newest')
19
20
  expect(category.identifier).to eq(plex_delegate.key)
20
- expect(category.modified_at).to eq(Time.at(plex_delegate.updated_at))
21
+ expect(category.modified_at).to eq(Time.at(plex_delegate.updated_at.to_i))
21
22
  expect(category.created_at).to eq(now)
22
23
  end
23
24
 
@@ -31,38 +32,110 @@ describe TivoHMO::Adapters::Plex::Category do
31
32
  expect(category.title).to eq('MyTitle')
32
33
  end
33
34
 
35
+ it "should set presorted if present" do
36
+ cval = {title: 'MyTitle', key: '/plex/key'}
37
+ category = described_class.new(plex_delegate, :by_year, nil, true)
38
+ expect(category.presorted).to eq(true)
39
+ end
40
+
34
41
  end
35
42
 
36
43
  describe "#children" do
37
44
 
38
45
  it "should memoize" do
39
- listing = [plex_stub(::Plex::Movie, originally_available_at: "2013-01-02")]
40
- allow(plex_delegate).to receive(:newest).and_return(listing)
41
46
  section = described_class.new(plex_delegate, :newest)
42
47
  expect(section.children.object_id).to eq(section.children.object_id)
43
48
  end
44
49
 
45
50
  it "should have children" do
46
- listing = [
47
- plex_stub(::Plex::Movie, originally_available_at: "2013-01-02"),
48
- plex_stub(::Plex::Episode, originally_available_at: "2013-01-02"),
49
- plex_stub(::Plex::Show)
50
- ]
51
- allow(plex_delegate).to receive(:newest).and_return(listing)
52
51
  section = described_class.new(plex_delegate, :newest)
53
- expect(section.children.size).to eq(3)
52
+
53
+ expect(section.children.size).to_not be(0)
54
+
55
+ keys = section.children.collect(&:delegate).collect(&:key)
56
+ expected_keys = plex_delegate.newest.collect(&:key)
57
+ expect(keys).to include(*expected_keys)
58
+ end
59
+
60
+ it "should display non-zero child_count once children fetched" do
61
+ section = described_class.new(plex_delegate, :newest)
62
+
63
+ expect(section.child_count).to be(0)
64
+ section.children
65
+ expect(section.child_count).to_not be(0)
66
+ expect(section.child_count).to eq(section.children.size)
67
+ end
68
+
69
+ it "should have children with subtitles" do
70
+ section = described_class.new(plex_delegate, :newest)
71
+
72
+ subgroup = section.children.find {|c| c.is_a?(TivoHMO::Adapters::Plex::Group) }
73
+ expect(subgroup).to_not be_nil
74
+ primary = subgroup.children[0]
75
+ sub = subgroup.children[1]
76
+ expect(primary.title).to_not match(/sub\]/)
77
+ expect(sub.title).to match(primary.title)
78
+ expect(sub.title).to match(/sub\]/)
79
+ expect(sub.subtitle.language).to_not be_nil
80
+ expect(sub.subtitle.language_code).to_not be_nil
81
+ expect(sub.subtitle.location).to_not be_nil
82
+
83
+ withoutsub = section.children.find {|c| ! c.is_a?(TivoHMO::Adapters::Plex::Group) }
84
+ expect(withoutsub).to_not be_nil
85
+ end
86
+
87
+ it "should have children with embedded subtitles" do
88
+ section = described_class.new(plex_delegate, :newest)
89
+
90
+ subgroup = section.children.find {|c|
91
+ c.is_a?(TivoHMO::Adapters::Plex::Group) &&
92
+ c.children.any? {|m| m.subtitle && m.subtitle.language == 'Embedded' }
93
+ }
94
+ expect(subgroup).to_not be_nil
95
+ primary = subgroup.children[0]
96
+ sub = subgroup.children[1]
97
+ expect(primary.title).to_not match(/sub\]/)
98
+ expect(sub.title).to match(primary.title)
99
+ expect(sub.title).to match(/sub\]/)
100
+ expect(sub.subtitle.language).to eq('Embedded')
101
+ expect(sub.subtitle.language_code).to_not be_nil
102
+ expect(sub.subtitle.location).to eq(0)
103
+ end
104
+
105
+ it "should allow disabling subtitles" do
106
+ section = described_class.new(plex_delegate, :newest)
107
+ described_class.config_set(:enable_subtitles, false)
108
+ withsub = section.children.find {|c| c.is_a?(TivoHMO::Adapters::Plex::Group) }
109
+ expect(withsub).to be_nil
54
110
  end
55
111
 
112
+ it "should refresh children when config changes" do
113
+ described_class.config_set(:enable_subtitles, false)
114
+ section = described_class.new(plex_delegate, :newest)
115
+
116
+ withsub = section.children.select {|c| c.is_a?(TivoHMO::Adapters::Plex::Group) }
117
+ withoutsub = section.children.select {|c| ! c.is_a?(TivoHMO::Adapters::Plex::Group) }
118
+ expect(withsub).to be_empty
119
+ expect(withoutsub).to_not be_empty
120
+
121
+ described_class.config_set(:enable_subtitles, true)
122
+
123
+ withsub = section.children.select {|c| c.is_a?(TivoHMO::Adapters::Plex::Group) }
124
+ withoutsub = section.children.select {|c| ! c.is_a?(TivoHMO::Adapters::Plex::Group) }
125
+ expect(withsub).to_not be_empty
126
+ expect(withoutsub).to_not be_empty
127
+ end
128
+
129
+
56
130
  it "should use category_value for children" do
57
- listing = [
58
- plex_stub(::Plex::Movie, originally_available_at: "2013-01-02"),
59
- plex_stub(::Plex::Episode, originally_available_at: "2013-01-02"),
60
- plex_stub(::Plex::Show)
61
- ]
62
- cval = {title: 'Title', key: 'key'}
63
- allow(plex_delegate).to receive(:by_year).with('key').and_return(listing)
131
+ cval = plex_delegate.years.first
64
132
  section = described_class.new(plex_delegate, :by_year, cval)
65
- expect(section.children.size).to eq(3)
133
+
134
+ expect(section.children.size).to_not be(0)
135
+
136
+ keys = section.children.collect(&:delegate).collect(&:key)
137
+ expected_keys = plex_delegate.by_year(cval[:key]).collect(&:key)
138
+ expect(keys).to include(*expected_keys)
66
139
  end
67
140
 
68
141
  end
@@ -1,15 +1,14 @@
1
1
  require_relative "../../spec_helper"
2
2
  require 'tivohmo/adapters/plex'
3
3
 
4
- describe TivoHMO::Adapters::Plex::Episode do
4
+ describe TivoHMO::Adapters::Plex::Episode, :vcr do
5
5
 
6
- let(:plex_delegate) { plex_stub(::Plex::Episode,
7
- content_rating: 'G',
8
- index: 2,
9
- parent_index: 1,
10
- grandparent_title: 'ShowTitle',
11
- guid: "com.plexapp.agents.thetvdb://269650/1/2?lang=en",
12
- originally_available_at: "2014-06-04") }
6
+ let(:plex_delegate) {
7
+ section = plex_tv_section
8
+ show = section.all.first
9
+ season = show.seasons.first
10
+ season.episodes.first
11
+ }
13
12
 
14
13
  describe "#initialize" do
15
14
 
@@ -19,7 +18,9 @@ describe TivoHMO::Adapters::Plex::Episode do
19
18
  expect(episode).to be_a TivoHMO::API::Item
20
19
  expect(episode.title).to eq(plex_delegate.title)
21
20
  expect(episode.identifier).to eq(plex_delegate.key)
22
- expect(episode.modified_at).to eq(Time.at(plex_delegate.updated_at))
21
+ expect(episode.file).to be_truthy
22
+ expect(episode.subtitle).to be_nil
23
+ expect(episode.modified_at).to eq(Time.at(plex_delegate.updated_at.to_i))
23
24
  expect(episode.created_at).to eq(Time.parse(plex_delegate.originally_available_at))
24
25
  end
25
26
 
@@ -32,13 +33,31 @@ describe TivoHMO::Adapters::Plex::Episode do
32
33
  episode.app = TivoHMO::Adapters::Plex::Application.new('localhost')
33
34
  md = episode.metadata
34
35
  expect(md.original_air_date).to eq(Time.parse(plex_delegate.originally_available_at))
35
- expect(md.tv_rating).to eq({name: 'G', value: 3})
36
+ rating = plex_delegate.content_rating.upcase
37
+ expect(md.tv_rating).to eq({name: rating,
38
+ value: TivoHMO::API::Metadata::TV_RATINGS[rating]})
36
39
  expect(md.is_episode).to eq(true)
37
- expect(md.episode_number).to eq("102")
38
- expect(md.series_title).to eq("ShowTitle")
39
- expect(md.episode_title).to eq("102 - Title")
40
- expect(md.title).to eq("ShowTitle - Title")
41
- expect(md.series_id).to eq("SH269650")
40
+ epnum = "%i%02i" % [plex_delegate.parent_index, plex_delegate.index]
41
+ expect(md.episode_number).to eq(epnum)
42
+ expect(md.series_title).to eq(plex_delegate.grandparent_title)
43
+ expect(md.episode_title).to eq("#{epnum} - #{plex_delegate.title}")
44
+ expect(md.title).to eq("#{plex_delegate.grandparent_title} - #{plex_delegate.title}")
45
+ expect(md.series_id).to match(/SH[0-9]+/)
46
+ end
47
+
48
+ it "should allow disabling series id in metadata" do
49
+ described_class.config_set(:group_with_zap2it, true)
50
+ episode = described_class.new(plex_delegate)
51
+ episode.app = TivoHMO::Adapters::Plex::Application.new('localhost')
52
+ md = episode.metadata
53
+ normal_series_id = md.series_id
54
+ expect(normal_series_id).to match(/SH[0-9]+/)
55
+
56
+ described_class.config_set(:group_with_zap2it, false)
57
+ md = episode.metadata
58
+ zap2it_series_id = md.series_id
59
+ expect(zap2it_series_id).to match(/SH[0-9]+/)
60
+ expect(zap2it_series_id).to_not eq(normal_series_id)
42
61
  end
43
62
 
44
63
  end
@@ -1,12 +1,9 @@
1
1
  require_relative "../../spec_helper"
2
2
  require 'tivohmo/adapters/plex'
3
3
 
4
- describe TivoHMO::Adapters::Plex::Metadata do
4
+ describe TivoHMO::Adapters::Plex::Metadata, :vcr do
5
5
 
6
- let(:plex_delegate) { plex_stub(::Plex::Movie,
7
- summary: 'Summary',
8
- duration: 10000,
9
- rating: 10) }
6
+ let(:plex_delegate) { plex_movie_section.all.first }
10
7
 
11
8
  let(:item) { double('item', delegate: plex_delegate)}
12
9
 
@@ -16,9 +13,10 @@ describe TivoHMO::Adapters::Plex::Metadata do
16
13
  md = described_class.new(item)
17
14
  expect(md).to be_a described_class
18
15
  expect(md).to be_a TivoHMO::API::Metadata
19
- expect(md.duration).to eq(plex_delegate.duration / 1000)
16
+ expect(md.duration).to eq(plex_delegate.duration.to_i / 1000)
20
17
  expect(md.description).to eq plex_delegate.summary
21
- expect(md.star_rating).to eq({name: 4, value: 7})
18
+ expect(md.star_rating[:name]).to be_nonzero
19
+ expect(md.star_rating[:value]).to be_nonzero
22
20
  end
23
21
 
24
22
  end
@@ -1,11 +1,9 @@
1
1
  require_relative "../../spec_helper"
2
2
  require 'tivohmo/adapters/plex'
3
3
 
4
- describe TivoHMO::Adapters::Plex::Movie do
4
+ describe TivoHMO::Adapters::Plex::Movie, :vcr do
5
5
 
6
- let(:plex_delegate) { plex_stub(::Plex::Movie,
7
- originally_available_at: "2013-01-02",
8
- content_rating: 'G') }
6
+ let(:plex_delegate) { plex_movie_section.all.first }
9
7
 
10
8
  describe "#initialize" do
11
9
 
@@ -15,7 +13,9 @@ describe TivoHMO::Adapters::Plex::Movie do
15
13
  expect(movie).to be_a TivoHMO::API::Item
16
14
  expect(movie.title).to eq(plex_delegate.title)
17
15
  expect(movie.identifier).to eq(plex_delegate.key)
18
- expect(movie.modified_at).to eq(Time.at(plex_delegate.updated_at))
16
+ expect(movie.file).to be_truthy
17
+ expect(movie.subtitle).to be_nil
18
+ expect(movie.modified_at).to eq(Time.at(plex_delegate.updated_at.to_i))
19
19
  expect(movie.created_at).to eq(Time.parse(plex_delegate.originally_available_at))
20
20
  end
21
21
 
@@ -27,8 +27,11 @@ describe TivoHMO::Adapters::Plex::Movie do
27
27
  movie = described_class.new(plex_delegate)
28
28
  movie.app = TivoHMO::Adapters::Plex::Application.new('localhost')
29
29
  md = movie.metadata
30
- expect(md.movie_year).to eq(2013)
31
- expect(md.mpaa_rating).to eq({name: 'G', value: 1})
30
+ expect(md.movie_year).to eq(plex_delegate.year.to_i)
31
+ rating = plex_delegate.content_rating.upcase
32
+ expect(md.mpaa_rating).to eq({name: rating,
33
+ value: TivoHMO::API::Metadata::MPAA_RATINGS[rating]})
34
+
32
35
  end
33
36
 
34
37
  end
@@ -1,9 +1,9 @@
1
1
  require_relative "../../spec_helper"
2
2
  require 'tivohmo/adapters/plex'
3
3
 
4
- describe TivoHMO::Adapters::Plex::QualifiedCategory do
4
+ describe TivoHMO::Adapters::Plex::QualifiedCategory, :vcr do
5
5
 
6
- let(:plex_delegate) { plex_stub(::Plex::Section) }
6
+ let(:plex_delegate) { plex_movie_section }
7
7
 
8
8
 
9
9
  describe "#initialize" do
@@ -16,9 +16,10 @@ describe TivoHMO::Adapters::Plex::QualifiedCategory do
16
16
  expect(qcat).to be_a TivoHMO::API::Container
17
17
  expect(qcat.title).to eq("By Year")
18
18
  expect(qcat.category_qualifier).to eq('2000')
19
+ expect(qcat.presorted).to eq(true)
19
20
  expect(qcat.title).to eq("By Year")
20
21
  expect(qcat.identifier).to eq(plex_delegate.key)
21
- expect(qcat.modified_at).to eq(Time.at(plex_delegate.updated_at))
22
+ expect(qcat.modified_at).to eq(Time.at(plex_delegate.updated_at.to_i))
22
23
  expect(qcat.created_at).to eq(now)
23
24
  end
24
25
  end
@@ -28,27 +29,26 @@ describe TivoHMO::Adapters::Plex::QualifiedCategory do
28
29
  describe "#children" do
29
30
 
30
31
  it "should memoize" do
31
- listing = [
32
- {title: 'Title1', key: 'key1'}
33
- ]
34
- allow(plex_delegate).to receive(:years).and_return(listing)
35
32
  section = described_class.new(plex_delegate, :by_year, :years)
36
33
  expect(section.children.object_id).to eq(section.children.object_id)
37
34
  end
38
35
 
39
36
  it "should have children" do
40
- listing = [
41
- {title: 'Title1', key: 'key1'},
42
- {title: 'Title2', key: 'key2'}
43
- ]
44
- allow(plex_delegate).to receive(:years).and_return(listing)
45
37
  section = described_class.new(plex_delegate, :by_year, :years)
46
- expect(section.children.size).to eq(2)
47
- expect(section.children[0]).to be_instance_of(TivoHMO::Adapters::Plex::Category)
48
- expect(section.children[0].category_type).to be(:by_year)
38
+ expect(section.children).to_not be_empty
39
+ section.children.all? {|c| expect(c).to be_instance_of(TivoHMO::Adapters::Plex::Category) }
40
+ section.children.all? {|c| expect(c.category_type).to be(:by_year) }
49
41
  # 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])
42
+ expect(section.children[1].category_value[:key]).to be > section.children[0].category_value[:key]
43
+ end
44
+
45
+ it "should display non-zero child_count once children fetched" do
46
+ section = described_class.new(plex_delegate, :by_year, :years)
47
+
48
+ expect(section.child_count).to be(0)
49
+ section.children
50
+ expect(section.child_count).to_not be(0)
51
+ expect(section.child_count).to eq(section.children.size)
52
52
  end
53
53
 
54
54
  end
@@ -1,9 +1,13 @@
1
1
  require_relative "../../spec_helper"
2
2
  require 'tivohmo/adapters/plex'
3
3
 
4
- describe TivoHMO::Adapters::Plex::Season do
4
+ describe TivoHMO::Adapters::Plex::Season, :vcr do
5
5
 
6
- let(:plex_delegate) { plex_stub(::Plex::Season) }
6
+ let(:plex_delegate) {
7
+ section = plex_tv_section
8
+ show = section.all.first
9
+ show.seasons.first
10
+ }
7
11
 
8
12
  describe "#initialize" do
9
13
 
@@ -13,10 +17,25 @@ describe TivoHMO::Adapters::Plex::Season do
13
17
  expect(season).to be_a TivoHMO::API::Container
14
18
  expect(season.title).to eq(plex_delegate.title)
15
19
  expect(season.identifier).to eq(plex_delegate.key)
16
- # expect(app.modified_at).to eq(Time.at(plex_delegate.updated_at))
17
- # expect(app.created_at).to eq(Time.at(plex_delegate.added_at))
20
+ expect(season.modified_at).to eq(Time.at(plex_delegate.updated_at.to_i))
21
+ expect(season.created_at).to eq(Time.at(plex_delegate.added_at.to_i))
18
22
  end
19
23
 
20
24
  end
21
25
 
26
+ describe "#children" do
27
+
28
+ it "should memoize" do
29
+ season = described_class.new(plex_delegate)
30
+ expect(season.children.object_id).to eq(season.children.object_id)
31
+ end
32
+
33
+ it "should have children" do
34
+ season = described_class.new(plex_delegate)
35
+ expect(season.children).to_not be_empty
36
+ season.children.all? {|c| expect(c).to be_instance_of(TivoHMO::Adapters::Plex::Episode) }
37
+ end
38
+
39
+ end
40
+
22
41
  end
@@ -1,9 +1,9 @@
1
1
  require_relative "../../spec_helper"
2
2
  require 'tivohmo/adapters/plex'
3
3
 
4
- describe TivoHMO::Adapters::Plex::Section do
4
+ describe TivoHMO::Adapters::Plex::Section, :vcr do
5
5
 
6
- let(:plex_delegate) { plex_stub(::Plex::Section) }
6
+ let(:plex_delegate) { plex_movie_section }
7
7
 
8
8
  describe "#initialize" do
9
9
 
@@ -15,7 +15,7 @@ describe TivoHMO::Adapters::Plex::Section do
15
15
  expect(section).to be_a TivoHMO::API::Container
16
16
  expect(section.title).to eq(plex_delegate.title)
17
17
  expect(section.identifier).to eq(plex_delegate.key)
18
- expect(section.modified_at).to eq(Time.at(plex_delegate.updated_at))
18
+ expect(section.modified_at).to eq(Time.at(plex_delegate.updated_at.to_i))
19
19
  expect(section.created_at).to eq(now)
20
20
  end
21
21
  end
@@ -31,7 +31,7 @@ describe TivoHMO::Adapters::Plex::Section do
31
31
 
32
32
  it "should have category children" do
33
33
  section = described_class.new(plex_delegate)
34
- expect(section.children.size).to eq(11)
34
+ expect(section.children.size).to_not be(0)
35
35
  classes = [TivoHMO::Adapters::Plex::Category, TivoHMO::Adapters::Plex::QualifiedCategory]
36
36
  expect(section.children.collect(&:class).uniq.sort_by(&:name)).to eq(classes.sort_by(&:name))
37
37
  end