tivohmo 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +17 -0
- data/.travis.yml +10 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +514 -0
- data/README.md +50 -0
- data/Rakefile +7 -0
- data/bin/tivohmo +8 -0
- data/contrib/tivohmo.conf +17 -0
- data/contrib/tivohmo.plist +22 -0
- data/lib/tivohmo/adapters/filesystem/application.rb +23 -0
- data/lib/tivohmo/adapters/filesystem/file_item.rb +29 -0
- data/lib/tivohmo/adapters/filesystem/folder_container.rb +105 -0
- data/lib/tivohmo/adapters/filesystem.rb +3 -0
- data/lib/tivohmo/adapters/plex/application.rb +41 -0
- data/lib/tivohmo/adapters/plex/category.rb +72 -0
- data/lib/tivohmo/adapters/plex/episode.rb +26 -0
- data/lib/tivohmo/adapters/plex/metadata.rb +24 -0
- data/lib/tivohmo/adapters/plex/movie.rb +26 -0
- data/lib/tivohmo/adapters/plex/qualified_category.rb +51 -0
- data/lib/tivohmo/adapters/plex/season.rb +39 -0
- data/lib/tivohmo/adapters/plex/section.rb +48 -0
- data/lib/tivohmo/adapters/plex/show.rb +39 -0
- data/lib/tivohmo/adapters/plex/transcoder.rb +19 -0
- data/lib/tivohmo/adapters/plex.rb +11 -0
- data/lib/tivohmo/adapters/streamio/metadata.rb +26 -0
- data/lib/tivohmo/adapters/streamio/transcoder.rb +239 -0
- data/lib/tivohmo/adapters/streamio.rb +17 -0
- data/lib/tivohmo/api/application.rb +35 -0
- data/lib/tivohmo/api/container.rb +31 -0
- data/lib/tivohmo/api/item.rb +32 -0
- data/lib/tivohmo/api/metadata.rb +98 -0
- data/lib/tivohmo/api/node.rb +115 -0
- data/lib/tivohmo/api/server.rb +24 -0
- data/lib/tivohmo/api/transcoder.rb +39 -0
- data/lib/tivohmo/api.rb +7 -0
- data/lib/tivohmo/beacon.rb +69 -0
- data/lib/tivohmo/cli.rb +182 -0
- data/lib/tivohmo/logging.rb +50 -0
- data/lib/tivohmo/server/views/_container.builder +19 -0
- data/lib/tivohmo/server/views/_item.builder +57 -0
- data/lib/tivohmo/server/views/container.builder +26 -0
- data/lib/tivohmo/server/views/item_details.builder +153 -0
- data/lib/tivohmo/server/views/layout.builder +2 -0
- data/lib/tivohmo/server/views/layout.erb +10 -0
- data/lib/tivohmo/server/views/server.builder +18 -0
- data/lib/tivohmo/server/views/server_info.builder +7 -0
- data/lib/tivohmo/server/views/unsupported.erb +7 -0
- data/lib/tivohmo/server/views/video_formats.builder +10 -0
- data/lib/tivohmo/server.rb +306 -0
- data/lib/tivohmo/version.rb +3 -0
- data/lib/tivohmo.rb +5 -0
- data/spec/adapters/filesystem/application_spec.rb +19 -0
- data/spec/adapters/filesystem/file_item_spec.rb +33 -0
- data/spec/adapters/filesystem/folder_container_spec.rb +115 -0
- data/spec/adapters/plex/application_spec.rb +20 -0
- data/spec/adapters/plex/category_spec.rb +66 -0
- data/spec/adapters/plex/episode_spec.rb +22 -0
- data/spec/adapters/plex/metadata_spec.rb +24 -0
- data/spec/adapters/plex/movie_spec.rb +22 -0
- data/spec/adapters/plex/qualified_category_spec.rb +51 -0
- data/spec/adapters/plex/season_spec.rb +22 -0
- data/spec/adapters/plex/section_spec.rb +38 -0
- data/spec/adapters/plex/show_spec.rb +22 -0
- data/spec/adapters/plex/transcoder_spec.rb +27 -0
- data/spec/adapters/streamio/metadata_spec.rb +34 -0
- data/spec/adapters/streamio/transcoder_spec.rb +42 -0
- data/spec/api/application_spec.rb +63 -0
- data/spec/api/container_spec.rb +34 -0
- data/spec/api/item_spec.rb +53 -0
- data/spec/api/metadata_spec.rb +59 -0
- data/spec/api/node_spec.rb +178 -0
- data/spec/api/server_spec.rb +24 -0
- data/spec/api/transcoder_spec.rb +25 -0
- data/spec/beacon_spec.rb +87 -0
- data/spec/cli_spec.rb +227 -0
- data/spec/server_spec.rb +458 -0
- data/spec/spec_helper.rb +123 -0
- data/tivohmo.gemspec +46 -0
- metadata +416 -0
data/spec/beacon_spec.rb
ADDED
@@ -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
|