tivohmo 0.1.0

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.
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