tivohmo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +17 -0
  4. data/.travis.yml +10 -0
  5. data/Gemfile +7 -0
  6. data/LICENSE.txt +514 -0
  7. data/README.md +50 -0
  8. data/Rakefile +7 -0
  9. data/bin/tivohmo +8 -0
  10. data/contrib/tivohmo.conf +17 -0
  11. data/contrib/tivohmo.plist +22 -0
  12. data/lib/tivohmo/adapters/filesystem/application.rb +23 -0
  13. data/lib/tivohmo/adapters/filesystem/file_item.rb +29 -0
  14. data/lib/tivohmo/adapters/filesystem/folder_container.rb +105 -0
  15. data/lib/tivohmo/adapters/filesystem.rb +3 -0
  16. data/lib/tivohmo/adapters/plex/application.rb +41 -0
  17. data/lib/tivohmo/adapters/plex/category.rb +72 -0
  18. data/lib/tivohmo/adapters/plex/episode.rb +26 -0
  19. data/lib/tivohmo/adapters/plex/metadata.rb +24 -0
  20. data/lib/tivohmo/adapters/plex/movie.rb +26 -0
  21. data/lib/tivohmo/adapters/plex/qualified_category.rb +51 -0
  22. data/lib/tivohmo/adapters/plex/season.rb +39 -0
  23. data/lib/tivohmo/adapters/plex/section.rb +48 -0
  24. data/lib/tivohmo/adapters/plex/show.rb +39 -0
  25. data/lib/tivohmo/adapters/plex/transcoder.rb +19 -0
  26. data/lib/tivohmo/adapters/plex.rb +11 -0
  27. data/lib/tivohmo/adapters/streamio/metadata.rb +26 -0
  28. data/lib/tivohmo/adapters/streamio/transcoder.rb +239 -0
  29. data/lib/tivohmo/adapters/streamio.rb +17 -0
  30. data/lib/tivohmo/api/application.rb +35 -0
  31. data/lib/tivohmo/api/container.rb +31 -0
  32. data/lib/tivohmo/api/item.rb +32 -0
  33. data/lib/tivohmo/api/metadata.rb +98 -0
  34. data/lib/tivohmo/api/node.rb +115 -0
  35. data/lib/tivohmo/api/server.rb +24 -0
  36. data/lib/tivohmo/api/transcoder.rb +39 -0
  37. data/lib/tivohmo/api.rb +7 -0
  38. data/lib/tivohmo/beacon.rb +69 -0
  39. data/lib/tivohmo/cli.rb +182 -0
  40. data/lib/tivohmo/logging.rb +50 -0
  41. data/lib/tivohmo/server/views/_container.builder +19 -0
  42. data/lib/tivohmo/server/views/_item.builder +57 -0
  43. data/lib/tivohmo/server/views/container.builder +26 -0
  44. data/lib/tivohmo/server/views/item_details.builder +153 -0
  45. data/lib/tivohmo/server/views/layout.builder +2 -0
  46. data/lib/tivohmo/server/views/layout.erb +10 -0
  47. data/lib/tivohmo/server/views/server.builder +18 -0
  48. data/lib/tivohmo/server/views/server_info.builder +7 -0
  49. data/lib/tivohmo/server/views/unsupported.erb +7 -0
  50. data/lib/tivohmo/server/views/video_formats.builder +10 -0
  51. data/lib/tivohmo/server.rb +306 -0
  52. data/lib/tivohmo/version.rb +3 -0
  53. data/lib/tivohmo.rb +5 -0
  54. data/spec/adapters/filesystem/application_spec.rb +19 -0
  55. data/spec/adapters/filesystem/file_item_spec.rb +33 -0
  56. data/spec/adapters/filesystem/folder_container_spec.rb +115 -0
  57. data/spec/adapters/plex/application_spec.rb +20 -0
  58. data/spec/adapters/plex/category_spec.rb +66 -0
  59. data/spec/adapters/plex/episode_spec.rb +22 -0
  60. data/spec/adapters/plex/metadata_spec.rb +24 -0
  61. data/spec/adapters/plex/movie_spec.rb +22 -0
  62. data/spec/adapters/plex/qualified_category_spec.rb +51 -0
  63. data/spec/adapters/plex/season_spec.rb +22 -0
  64. data/spec/adapters/plex/section_spec.rb +38 -0
  65. data/spec/adapters/plex/show_spec.rb +22 -0
  66. data/spec/adapters/plex/transcoder_spec.rb +27 -0
  67. data/spec/adapters/streamio/metadata_spec.rb +34 -0
  68. data/spec/adapters/streamio/transcoder_spec.rb +42 -0
  69. data/spec/api/application_spec.rb +63 -0
  70. data/spec/api/container_spec.rb +34 -0
  71. data/spec/api/item_spec.rb +53 -0
  72. data/spec/api/metadata_spec.rb +59 -0
  73. data/spec/api/node_spec.rb +178 -0
  74. data/spec/api/server_spec.rb +24 -0
  75. data/spec/api/transcoder_spec.rb +25 -0
  76. data/spec/beacon_spec.rb +87 -0
  77. data/spec/cli_spec.rb +227 -0
  78. data/spec/server_spec.rb +458 -0
  79. data/spec/spec_helper.rb +123 -0
  80. data/tivohmo.gemspec +46 -0
  81. metadata +416 -0
@@ -0,0 +1,87 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe TivoHMO::Beacon do
4
+
5
+
6
+ describe "#initialize" do
7
+
8
+ it "should instantiate with defaults" do
9
+ beacon = described_class.new(1234)
10
+ expect(beacon).to be_a described_class
11
+ expect(beacon.instance_variable_get(:@limit)).to eq(-1)
12
+ expect(beacon.instance_variable_get(:@interval)).to eq(60)
13
+ expect(beacon.instance_variable_get(:@services)).to eq(['TiVoMediaServer:1234/http'])
14
+ end
15
+
16
+ it "should instantiate with limit" do
17
+ beacon = described_class.new(1234, limit: 5)
18
+ expect(beacon.instance_variable_get(:@limit)).to eq(5)
19
+ end
20
+
21
+ it "should instantiate with interval" do
22
+ beacon = described_class.new(1234, interval: 4)
23
+ expect(beacon.instance_variable_get(:@interval)).to eq(4)
24
+ end
25
+
26
+ end
27
+
28
+ describe "#beacon_data" do
29
+
30
+ before(:each) do
31
+ @beacon = described_class.new(1234)
32
+ end
33
+
34
+ it "generates beacon packet" do
35
+ data = %W[
36
+ tivoconnect=1
37
+ method=broadcast
38
+ identity={#{@beacon.instance_variable_get(:@uid)}}
39
+ machine=#{Socket.gethostname}
40
+ platform=pc/tivohmo
41
+ services=#{@beacon.instance_variable_get(:@services).join(';')}
42
+ swversion=#{TivoHMO::VERSION}
43
+ ]
44
+
45
+ expect(@beacon.beacon_data('broadcast')).to eq(data.join("\n") + "\n")
46
+ end
47
+
48
+ end
49
+
50
+ describe "#start/stop/join" do
51
+
52
+ it "runs for limit times sleeping for interval" do
53
+ beacon = described_class.new(1234, limit: 2, interval: 0.1)
54
+ expect(beacon).to receive(:sleep).with(0.1).twice
55
+ expect(beacon).to receive(:broadcast).twice
56
+ expect(beacon.instance_variable_get(:@running)).to eq(false)
57
+ beacon.start
58
+ expect(beacon.instance_variable_get(:@running)).to eq(true)
59
+ beacon.join
60
+ expect(beacon.instance_variable_get(:@running)).to eq(false)
61
+ end
62
+
63
+ it "runs indefinately for -1 limit" do
64
+ beacon = described_class.new(1234, limit: -1, interval: 0.001)
65
+ expect(beacon).to receive(:sleep).with(0.001).at_least(5).times
66
+ expect(beacon).to receive(:broadcast).at_least(5).times
67
+ beacon.start
68
+ sleep(0.1)
69
+ beacon.stop
70
+ beacon.join
71
+ end
72
+
73
+ end
74
+
75
+ describe "#broadcast" do
76
+
77
+ it "sends a packet on the socket" do
78
+ beacon = described_class.new(1234)
79
+ expect(beacon).to receive(:beacon_data).with('broadcast').and_return('packet')
80
+ socket = beacon.instance_variable_get(:@socket)
81
+ expect(socket).to receive(:send).with('packet', 0, '<broadcast>', 2190)
82
+ beacon.broadcast
83
+ end
84
+
85
+ end
86
+
87
+ end
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,227 @@
1
+ require_relative "spec_helper"
2
+ require "tivohmo/cli"
3
+
4
+ describe TivoHMO::CLI do
5
+
6
+ let(:app_name) { TestAPI::Application.name }
7
+ let(:app_ident) { 'app_ident' }
8
+ let(:minimal_args) do
9
+ {
10
+ application: app_name,
11
+ identifier: app_ident
12
+ }
13
+ end
14
+ let(:api_server) { TivoHMO::API::Server.new }
15
+ let(:cli) { described_class.new("") }
16
+
17
+ def argv(arg)
18
+ if arg.is_a?(Hash)
19
+ arg.collect {|k, v| ["--#{k}", v]}.flatten
20
+ elsif arg.is_a?(Enumerable)
21
+ arg.each_slice(2).collect {|k, v| ["--#{k}", v]}.flatten
22
+ else
23
+ raise 'bad arg'
24
+ end
25
+ end
26
+
27
+ before(:each) do
28
+ # stub out server so erroneous tests don't block indefinately
29
+ allow(Rack::Handler.default).to receive(:run)
30
+ allow(TivoHMO::API::Server).to receive(:new).and_return(api_server)
31
+ end
32
+
33
+ describe "--help" do
34
+
35
+ it "produces help text under standard width" do
36
+ lines = described_class.new("").help.split("\n")
37
+ lines.each {|l| expect(l.size).to be <= 80 }
38
+ end
39
+
40
+ end
41
+
42
+ describe "--debug" do
43
+
44
+ it "defaults to info log level" do
45
+ expect(Logging.logger.root).to receive(:level=).with(:debug).never
46
+ cli.run(argv(minimal_args))
47
+ end
48
+
49
+ it "sets log level to debug" do
50
+ expect(Logging.logger.root).to receive(:level=).with(:debug)
51
+ cli.run(argv(minimal_args) + ['--debug'])
52
+ end
53
+
54
+ end
55
+
56
+ describe "--preload" do
57
+
58
+ it "defaults to not preloading" do
59
+ expect(cli).to receive(:preload_containers).never
60
+ cli.run(argv(minimal_args))
61
+ end
62
+
63
+ it "preloads all containers" do
64
+ expect(cli).to receive(:preload_containers).once.and_call_original
65
+ cli.run(argv(minimal_args) + ['--preload'])
66
+ end
67
+
68
+ end
69
+
70
+ describe "--logfile" do
71
+
72
+ it "defaults to stdout" do
73
+ cli.run(argv(minimal_args))
74
+ expect(Logging.logger.root.appenders.collect(&:name)).to include('stdout')
75
+ end
76
+
77
+ it "sets log to file" do
78
+ file = Tempfile.new('cli_spec').path
79
+ cli.run(argv(minimal_args.merge(logfile: file)))
80
+ expect(Logging.logger.root.appenders.collect(&:name)).to eq([file])
81
+ end
82
+
83
+ end
84
+
85
+ describe "--configuration" do
86
+
87
+ it "defaults to not loading config" do
88
+ expect(YAML).to receive(:load_file).never
89
+ cli.run(argv(minimal_args))
90
+ end
91
+
92
+ it "sets log level to debug" do
93
+ expect(YAML).to receive(:load_file).with('foo.yml').and_return({})
94
+ cli.run(argv(minimal_args.merge(configuration: 'foo.yml')))
95
+ end
96
+
97
+ it "can supply config" do
98
+ expect(YAML).to receive(:load_file).with('foo.yml').and_return({'port' => 1234})
99
+ expect(TivoHMO::Server).to receive(:start).with(api_server, 1234)
100
+ cli.run(argv(minimal_args.merge(configuration: 'foo.yml')))
101
+ end
102
+
103
+ it "supplies config that can be overriden from cli" do
104
+ expect(YAML).to receive(:load_file).with('foo.yml').and_return({'port' => 1234})
105
+ expect(TivoHMO::Server).to receive(:start).with(api_server, 4321)
106
+ cli.run(argv(minimal_args.merge(configuration: 'foo.yml', port: 4321)))
107
+ end
108
+
109
+ end
110
+
111
+ describe "--port" do
112
+
113
+ it "has a default port" do
114
+ expect(TivoHMO::Server).to receive(:start).with(api_server, 9032)
115
+ cli.run(argv(minimal_args))
116
+ end
117
+
118
+ it "provides a different port" do
119
+ expect(TivoHMO::Server).to receive(:start).with(api_server, 1234)
120
+ cli.run(argv(minimal_args.merge(port: 1234)))
121
+ end
122
+
123
+ end
124
+
125
+ describe "--beacon" do
126
+
127
+ it "works with defaults" do
128
+ expect(TivoHMO::Beacon).to receive(:new).with(9032, **{})
129
+ cli.run(argv(minimal_args))
130
+ end
131
+
132
+ it "can specify just a limit" do
133
+ expect(TivoHMO::Beacon).to receive(:new).with(9032, **{limit: 5})
134
+ cli.run(argv(minimal_args.merge(beacon: '5')))
135
+ end
136
+
137
+ it "can specify just an interval" do
138
+ expect(TivoHMO::Beacon).to receive(:new).with(9032, **{interval: 5})
139
+ cli.run(argv(minimal_args.merge(beacon: ':5')))
140
+ end
141
+
142
+ it "can specify both limit and interval" do
143
+ expect(TivoHMO::Beacon).to receive(:new).with(9032, **{limit: 5, interval: 6})
144
+ cli.run(argv(minimal_args.merge(beacon: '5:6')))
145
+ end
146
+
147
+ end
148
+
149
+ describe "requirements" do
150
+
151
+ it "requires one app" do
152
+ expect {
153
+ described_class.new("").run([])
154
+ }.to raise_error(Clamp::UsageError,
155
+ 'at least one application is required')
156
+ end
157
+
158
+ it "requires one init per app" do
159
+ expect {
160
+ described_class.new("").run(["-a", "foo"])
161
+ }.to raise_error(Clamp::UsageError,
162
+ 'an initializer is needed for each application')
163
+ end
164
+
165
+ end
166
+
167
+ describe "basic usage" do
168
+
169
+ before(:each) do
170
+ expect(TivoHMO::Server).to receive(:start).with(api_server, 9032)
171
+ end
172
+
173
+ it "requires the adapter for the application" do
174
+ require 'tivohmo/adapters/filesystem'
175
+ expect(cli).to receive(:require).with('tivohmo/adapters/filesystem')
176
+ cli.run(%w[-a TivoHMO::Adapters::Filesystem::Application -i .])
177
+ end
178
+
179
+ it "starts a server for the app" do
180
+ cli.run(argv(minimal_args))
181
+ expect(api_server.children.size).to eq(1)
182
+ expect(api_server.children.first.class).to eq(TestAPI::Application)
183
+ expect(api_server.children.first.title).to eq("#{app_ident} on #{api_server.title}")
184
+ end
185
+
186
+ it "starts a server with title" do
187
+ cli.run(argv(minimal_args.merge(title: 'Foo')))
188
+ expect(api_server.children.size).to eq(1)
189
+ expect(api_server.children.first.class).to eq(TestAPI::Application)
190
+ expect(api_server.children.first.title).to eq("Foo")
191
+ end
192
+
193
+ it "starts a server with alternate transcoder/metadata" do
194
+ cli.run(argv(minimal_args.merge(
195
+ transcoder: TivoHMO::API::Transcoder.name,
196
+ metadata: TivoHMO::API::Metadata.name
197
+ )))
198
+
199
+ default = TestAPI::Application.new('.')
200
+ expect(default.metadata_class).to_not eq(TivoHMO::API::Metadata)
201
+ expect(default.transcoder_class).to_not eq(TivoHMO::API::Transcoder)
202
+
203
+ expect(api_server.children.size).to eq(1)
204
+ expect(api_server.children.first.transcoder_class).to eq(TivoHMO::API::Transcoder)
205
+ expect(api_server.children.first.metadata_class).to eq(TivoHMO::API::Metadata)
206
+ end
207
+
208
+ it "starts a server with multiple apps" do
209
+ cli.run(argv(%W[
210
+ application #{TestAPI::Application.name}
211
+ identifier app_ident1
212
+ title App1
213
+ application #{TestAPI::Application.name}
214
+ identifier app_ident2
215
+ title App2
216
+ ]))
217
+
218
+ expect(api_server.children.size).to eq(2)
219
+ expect(api_server.children[0].identifier).to eq('app_ident1')
220
+ expect(api_server.children[1].identifier).to eq('app_ident2')
221
+ expect(api_server.children[0].title).to eq('App1')
222
+ expect(api_server.children[1].title).to eq('App2')
223
+ end
224
+
225
+ end
226
+
227
+ end