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,224 @@
1
+ require_relative "spec_helper"
2
+ require 'tempfile'
3
+
4
+ describe TivoHMO::Config do
5
+
6
+ before(:each) do
7
+ TivoHMO::Config.instance.reset
8
+ FileUtils.rm_f([primary, secondary])
9
+ end
10
+
11
+ let(:primary) do
12
+ Tempfile.new('primary').path
13
+ end
14
+
15
+ let(:secondary) do
16
+ Tempfile.new('secondary').path
17
+ end
18
+
19
+ describe ".setup" do
20
+
21
+ it "looks for primary and secondary" do
22
+ described_class.instance.setup(primary, secondary)
23
+ expect(described_class.instance.instance_variable_get(:@primary_file)).to eq(primary)
24
+ expect(described_class.instance.instance_variable_get(:@secondary_file)).to eq(secondary)
25
+ expect(described_class.instance.instance_variable_get(:@primary_data)).to eq({})
26
+ expect(described_class.instance.instance_variable_get(:@secondary_data)).to eq({})
27
+ end
28
+
29
+ it "loads in primary and secondary" do
30
+ File.write(primary, {'foo' => 'bar'}.to_yaml)
31
+ File.write(secondary, {'baz' => 'boo'}.to_yaml)
32
+ described_class.instance.setup(primary, secondary)
33
+ expect(described_class.instance.instance_variable_get(:@primary_data)).to eq({'foo' => 'bar'})
34
+ expect(described_class.instance.instance_variable_get(:@secondary_data)).to eq({'baz' => 'boo'})
35
+ end
36
+
37
+ it "uses primary to find secondary" do
38
+ File.write(primary, {'settings' => secondary}.to_yaml)
39
+ File.write(secondary, {'baz' => 'boo'}.to_yaml)
40
+ described_class.instance.setup(primary, nil)
41
+ expect(described_class.instance.instance_variable_get(:@primary_data)).to eq({'settings' => secondary})
42
+ expect(described_class.instance.instance_variable_get(:@secondary_data)).to eq({'baz' => 'boo'})
43
+ end
44
+
45
+ it "uses passed in secondary over settings in primary" do
46
+ other_secondary = Tempfile.new('other_secondary').path
47
+ File.write(primary, {'settings' => secondary}.to_yaml)
48
+ File.write(secondary, {'baz' => 'boo'}.to_yaml)
49
+ File.write(other_secondary, {'hum' => 'dum'}.to_yaml)
50
+ described_class.instance.setup(primary, other_secondary)
51
+ expect(described_class.instance.instance_variable_get(:@primary_data)).to eq({'settings' => secondary})
52
+ expect(described_class.instance.instance_variable_get(:@secondary_data)).to eq({'hum' => 'dum'})
53
+ end
54
+
55
+ end
56
+
57
+ describe "get" do
58
+
59
+ before(:each) do
60
+ File.write(primary, {'p1' => 'p1', 'p2' => 'p2', 'p3' => {'p4' => 'p4', 'p5' => 'p5'}}.to_yaml)
61
+ File.write(secondary, {'s1' => 's1', 'p2' => 's2', 'p3' => {'s4' => 's4', 'p5' => 's5'}}.to_yaml)
62
+ described_class.instance.setup(primary, secondary)
63
+ end
64
+
65
+ it "returns nil for miss" do
66
+ expect(described_class.instance.get(:nokey)).to be_nil
67
+ end
68
+
69
+ it "returns value from primary" do
70
+ expect(described_class.instance.get(:p1)).to eq('p1')
71
+ end
72
+
73
+ it "returns value from secondary" do
74
+ expect(described_class.instance.get(:s1)).to eq('s1')
75
+ end
76
+
77
+ it "returns override value from secondary" do
78
+ expect(described_class.instance.get(:p2)).to eq('s2')
79
+ end
80
+
81
+ it "returns primary deep value" do
82
+ expect(described_class.instance.get([:p3, :p4])).to eq('p4')
83
+ end
84
+
85
+ it "returns secondary deep value" do
86
+ expect(described_class.instance.get([:p3, :s4])).to eq('s4')
87
+ end
88
+
89
+ it "returns override secondary deep value" do
90
+ expect(described_class.instance.get([:p3, :p5])).to eq('s5')
91
+ end
92
+
93
+ end
94
+
95
+ describe "set" do
96
+
97
+ before(:each) do
98
+ File.write(primary, {'p1' => 'p1', 'p2' => 'p2', 'p3' => {'p4' => 'p4', 'p5' => 'p5'}}.to_yaml)
99
+ File.write(secondary, {'s1' => 's1', 'p2' => 's2', 'p3' => {'s4' => 's4', 'p5' => 's5'}}.to_yaml)
100
+ described_class.instance.setup(primary, secondary)
101
+ end
102
+
103
+ it "sets a value" do
104
+ described_class.instance.set(:s1, 'set1')
105
+ expect(described_class.instance.get(:s1)).to eq('set1')
106
+
107
+ described_class.instance.reset
108
+ described_class.instance.setup(primary, secondary)
109
+ expect(described_class.instance.get(:s1)).to eq('set1')
110
+ end
111
+
112
+ it "sets a value without saving" do
113
+ described_class.instance.set(:s1, 'set1', false)
114
+ expect(described_class.instance.get(:s1)).to eq('set1')
115
+
116
+ described_class.instance.reset
117
+ described_class.instance.setup(primary, secondary)
118
+ expect(described_class.instance.get(:s1)).to_not eq('set1')
119
+ end
120
+
121
+ it "sets a deep value" do
122
+ described_class.instance.set([:p3, :p5], 'set5')
123
+ expect(described_class.instance.get([:p3, :p5])).to eq('set5')
124
+
125
+ described_class.instance.reset
126
+ described_class.instance.setup(primary, secondary)
127
+ expect(described_class.instance.get([:p3, :p5])).to eq('set5')
128
+ end
129
+
130
+ end
131
+
132
+ describe TivoHMO::Config::Mixin do
133
+
134
+ class TestMixin
135
+ include TivoHMO::Config::Mixin
136
+ end
137
+
138
+ class TestMixin2
139
+ include TivoHMO::Config::Mixin
140
+ end
141
+
142
+ before(:each) do
143
+ File.write(primary, {'p1' => 'p1', 'p2' => 'p2', 'p3' => {'p4' => 'p4', 'p5' => 'p5'}}.to_yaml)
144
+ File.write(secondary, {'s1' => 's1', 'p2' => 's2', 'p3' => {'s4' => 's4', 'p5' => 's5'}}.to_yaml)
145
+ TivoHMO::Config.instance.setup(primary, secondary)
146
+ end
147
+
148
+ describe "config_register" do
149
+
150
+ it "allows registering a config once" do
151
+ expect(TivoHMO::Config.instance.known_config[:foo]).to be_nil
152
+ TestMixin.config_register(:foo, 3, "this is foo")
153
+ conf = TivoHMO::Config.instance.known_config[:foo]
154
+ expect(conf[:default_value]).to eq(3)
155
+ expect(conf[:description]).to eq("this is foo")
156
+ expect(conf[:source_path]).to eq(["test_mixin"])
157
+ expect(conf[:on_change]).to be_nil
158
+
159
+ expect {
160
+ TestMixin.config_register(:foo, 3, "this is foo")
161
+ }.to raise_error(ArgumentError, /already registered/)
162
+ end
163
+
164
+ it "calls change handler on change" do
165
+ called = 0
166
+ TestMixin.config_register(:foo, 3, "this is foo") do
167
+ called += 1
168
+ end
169
+ conf = TivoHMO::Config.instance.known_config[:foo]
170
+ expect(conf[:on_change]).to_not be_nil
171
+ TestMixin.config_set(:foo, 4)
172
+ expect(TestMixin.config_get(:foo)).to be (4)
173
+ expect(called).to be (1)
174
+ end
175
+
176
+ end
177
+
178
+ describe "config_get" do
179
+
180
+ it "allows getting config" do
181
+ expect(TestMixin.config_get(:p1)).to eq('p1')
182
+ end
183
+
184
+ it "allows getting registered config default" do
185
+ TestMixin.config_register(:foo, 3, "this is foo")
186
+ expect(TestMixin.config_get(:foo)).to eq(3)
187
+ end
188
+
189
+ it "allows getting config cross class" do
190
+ expect(TestMixin2.config_get(:p1)).to eq('p1')
191
+ end
192
+
193
+ it "allows getting registered config default cross class" do
194
+ TestMixin.config_register(:foo, 3, "this is foo")
195
+ expect(TestMixin2.config_get(:foo)).to eq(3)
196
+ end
197
+
198
+ it "allows independent config cross class" do
199
+ TestMixin.config_register(:foo, 3, "this is foo")
200
+ TivoHMO::Config.instance.set(['test_mixin', 'foo'], 'v1')
201
+ expect(TestMixin.config_get(:foo)).to eq('v1')
202
+ expect(TestMixin2.config_get(:foo)).to eq(3)
203
+ end
204
+
205
+ end
206
+
207
+ describe "config_set" do
208
+
209
+ it "allows setting config" do
210
+ TestMixin.config_set(:p1, 'set1')
211
+ expect(TestMixin.config_get(:p1)).to eq('set1')
212
+ end
213
+
214
+ it "allows setting registered config" do
215
+ TestMixin.config_register(:foo, 3, "this is foo")
216
+ TestMixin.config_set(:foo, 'set1')
217
+ expect(TestMixin.config_get(:foo)).to eq('set1')
218
+ end
219
+
220
+ end
221
+
222
+ end
223
+
224
+ end
@@ -0,0 +1,61 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://localhost:32400/library/sections
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - "*/*"
14
+ User-Agent:
15
+ - Ruby
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Content-Type:
22
+ - text/xml;charset=utf-8
23
+ Connection:
24
+ - close
25
+ X-Plex-Protocol:
26
+ - '1.0'
27
+ X-Plex-Content-Original-Length:
28
+ - '2991'
29
+ X-Plex-Content-Compressed-Length:
30
+ - '805'
31
+ Content-Length:
32
+ - '805'
33
+ Cache-Control:
34
+ - no-cache
35
+ body:
36
+ encoding: UTF-8
37
+ string: |
38
+ <?xml version="1.0" encoding="UTF-8"?>
39
+ <MediaContainer size="6" allowSync="0" identifier="com.plexapp.plugins.library" mediaTagPrefix="/system/bundle/media/flags/" mediaTagVersion="1420767545" title1="Plex Library">
40
+ <Directory allowSync="0" art="/:/resources/movie-fanart.jpg" filters="1" refreshing="0" thumb="/:/resources/movie.png" key="1" type="movie" title="Adult Movies" composite="/library/sections/1/composite/1423777283" agent="com.plexapp.agents.imdb" scanner="Plex Movie Scanner" language="en" uuid="9113e43dc6c547eede809f9439c8e80498b4a610" updatedAt="1423777283" createdAt="1332713366">
41
+ <Location id="4" path="/Users/mconway/Movies/Adult Movies" />
42
+ </Directory>
43
+ <Directory allowSync="0" art="/:/resources/show-fanart.jpg" filters="1" refreshing="0" thumb="/:/resources/show.png" key="2" type="show" title="Adult TV Shows" composite="/library/sections/2/composite/1423932892" agent="com.plexapp.agents.thetvdb" scanner="Plex Series Scanner" language="en" uuid="af8295a272d545681d462eed8025113d09195007" updatedAt="1423932892" createdAt="1332713366">
44
+ <Location id="6" path="/Users/mconway/Movies/Adult TV Shows" />
45
+ </Directory>
46
+ <Directory allowSync="0" art="/:/resources/movie-fanart.jpg" filters="1" refreshing="0" thumb="/:/resources/movie.png" key="5" type="movie" title="Kid Movies" composite="/library/sections/5/composite/1423777310" agent="com.plexapp.agents.imdb" scanner="Plex Movie Scanner" language="en" uuid="340479de-6015-4e6c-9ec0-c74f936f4013" updatedAt="1423777310" createdAt="1411071543">
47
+ <Location id="9" path="/Users/mconway/Movies/Kid Movies" />
48
+ </Directory>
49
+ <Directory allowSync="0" art="/:/resources/show-fanart.jpg" filters="1" refreshing="0" thumb="/:/resources/show.png" key="4" type="show" title="Kid TV Shows" composite="/library/sections/4/composite/1423777311" agent="com.plexapp.agents.thetvdb" scanner="Plex Series Scanner" language="en" uuid="fa1dde48-f6dd-44f7-91f3-9283160dc953" updatedAt="1423777311" createdAt="1411071497">
50
+ <Location id="8" path="/Users/mconway/Movies/Kid TV Shows" />
51
+ </Directory>
52
+ <Directory allowSync="0" art="/:/resources/movie-fanart.jpg" filters="1" refreshing="1" thumb="/:/resources/movie.png" key="6" type="movie" title="Test Movies" composite="/library/sections/6/composite/1423936036" agent="com.plexapp.agents.imdb" scanner="Plex Movie Scanner" language="en" uuid="fbc810b7-6b51-40ba-a3c5-9a2c391e5a3d" updatedAt="1423936036" createdAt="1423935251">
53
+ <Location id="10" path="/Users/mconway/Movies/TivoHMOTest/Movies" />
54
+ </Directory>
55
+ <Directory allowSync="0" art="/:/resources/show-fanart.jpg" filters="1" refreshing="0" thumb="/:/resources/show.png" key="7" type="show" title="Test TV Shows" composite="/library/sections/7/composite/1423935290" agent="com.plexapp.agents.thetvdb" scanner="Plex Series Scanner" language="en" uuid="4c37cd05-86d7-4a34-8d5b-aa2fb261a136" updatedAt="1423935290" createdAt="1423935290">
56
+ <Location id="11" path="/Users/mconway/Movies/TivoHMOTest/TV Shows" />
57
+ </Directory>
58
+ </MediaContainer>
59
+ http_version:
60
+ recorded_at: Sat, 14 Feb 2015 17:47:35 GMT
61
+ recorded_with: VCR 2.9.3