tivohmo 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG +30 -0
- data/Gemfile +2 -0
- data/README.md +4 -6
- data/TODO +1 -0
- data/contrib/tivohmo.conf +2 -2
- data/contrib/tivohmo.plist +1 -1
- data/contrib/tivohmo.yml +60 -0
- data/lib/tivohmo/adapters/filesystem/file_item.rb +2 -3
- data/lib/tivohmo/adapters/plex/category.rb +87 -6
- data/lib/tivohmo/adapters/plex/episode.rb +30 -11
- data/lib/tivohmo/adapters/plex/group.rb +20 -0
- data/lib/tivohmo/adapters/plex/movie.rb +15 -3
- data/lib/tivohmo/adapters/plex/qualified_category.rb +14 -3
- data/lib/tivohmo/adapters/plex/season.rb +2 -2
- data/lib/tivohmo/adapters/plex/section.rb +5 -5
- data/lib/tivohmo/adapters/plex/transcoder.rb +5 -1
- data/lib/tivohmo/adapters/plex.rb +1 -0
- data/lib/tivohmo/adapters/settings/application.rb +37 -0
- data/lib/tivohmo/adapters/settings/display_item.rb +35 -0
- data/lib/tivohmo/adapters/settings/key_container.rb +35 -0
- data/lib/tivohmo/adapters/settings/metadata.rb +26 -0
- data/lib/tivohmo/adapters/settings/reset_defaults_item.rb +39 -0
- data/lib/tivohmo/adapters/settings/set_value_item.rb +38 -0
- data/lib/tivohmo/adapters/settings/transcoder.rb +23 -0
- data/lib/tivohmo/adapters/settings.rb +7 -0
- data/lib/tivohmo/adapters/streamio/transcoder.rb +39 -1
- data/lib/tivohmo/api/container.rb +5 -1
- data/lib/tivohmo/api/item.rb +2 -0
- data/lib/tivohmo/api/subtitle.rb +13 -0
- data/lib/tivohmo/api/transcoder.rb +1 -3
- data/lib/tivohmo/api.rb +1 -0
- data/lib/tivohmo/beacon.rb +3 -3
- data/lib/tivohmo/cli.rb +175 -48
- data/lib/tivohmo/config.rb +157 -0
- data/lib/tivohmo/server/views/_container.builder +1 -1
- data/lib/tivohmo/server.rb +6 -3
- data/lib/tivohmo/version.rb +1 -1
- data/lib/tivohmo.rb +1 -0
- data/spec/adapters/filesystem/file_item_spec.rb +1 -1
- data/spec/adapters/plex/application_spec.rb +10 -1
- data/spec/adapters/plex/category_spec.rb +93 -20
- data/spec/adapters/plex/episode_spec.rb +34 -15
- data/spec/adapters/plex/metadata_spec.rb +5 -7
- data/spec/adapters/plex/movie_spec.rb +10 -7
- data/spec/adapters/plex/qualified_category_spec.rb +17 -17
- data/spec/adapters/plex/season_spec.rb +23 -4
- data/spec/adapters/plex/section_spec.rb +4 -4
- data/spec/adapters/plex/show_spec.rb +19 -4
- data/spec/adapters/plex/transcoder_spec.rb +2 -8
- data/spec/adapters/settings/application_spec.rb +25 -0
- data/spec/adapters/settings/display_item_spec.rb +29 -0
- data/spec/adapters/settings/key_container_spec.rb +33 -0
- data/spec/adapters/settings/metadata_spec.rb +33 -0
- data/spec/adapters/settings/reset_defaults_item_spec.rb +54 -0
- data/spec/adapters/settings/set_value_item_spec.rb +54 -0
- data/spec/api/container_spec.rb +12 -0
- data/spec/api/item_spec.rb +2 -0
- data/spec/api/transcoder_spec.rb +0 -1
- data/spec/beacon_spec.rb +3 -1
- data/spec/cli_spec.rb +57 -19
- data/spec/config_spec.rb +224 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Application/_children/should_get_children.yml +61 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_allow_disabling_subtitles.yml +424 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_display_non-zero_child_count_once_children_fetched.yml +653 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_have_children.yml +599 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_have_children_with_embedded_subtitles.yml +595 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_have_children_with_subtitles.yml +482 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_memoize.yml +478 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_refresh_children_when_config_changes.yml +1245 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_use_category_value_for_children.yml +395 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_initialize/should_instantiate.yml +61 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_initialize/should_set_presorted_if_present.yml +61 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_initialize/should_use_category_value_for_title_if_present.yml +61 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Episode/_initialize/should_instantiate.yml +444 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Episode/_metadata/should_allow_disabling_series_id_in_metadata.yml +444 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Episode/_metadata/should_populate_metadata.yml +579 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Metadata/_initialize/should_instantiate.yml +296 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Movie/_initialize/should_instantiate.yml +296 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Movie/_metadata/should_populate_metadata.yml +296 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_QualifiedCategory/_children/should_display_non-zero_child_count_once_children_fetched.yml +220 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_QualifiedCategory/_children/should_have_children.yml +393 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_QualifiedCategory/_children/should_memoize.yml +219 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_QualifiedCategory/_initialize/should_instantiate.yml +61 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Season/_children/should_have_children.yml +444 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Season/_children/should_memoize.yml +444 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Season/_initialize/should_instantiate.yml +250 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Section/_children/should_have_category_children.yml +61 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Section/_children/should_memoize.yml +61 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Section/_initialize/should_instantiate.yml +61 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Show/_children/should_have_children.yml +250 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Show/_children/should_memoize.yml +250 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Show/_initialize/should_instantiate.yml +166 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Transcoder/_initialize/should_instantiate.yml +296 -0
- data/spec/server_spec.rb +31 -2
- data/spec/spec_helper.rb +24 -36
- data/tivohmo.gemspec +2 -2
- metadata +109 -3
@@ -0,0 +1,35 @@
|
|
1
|
+
module TivoHMO
|
2
|
+
module Adapters
|
3
|
+
module Settings
|
4
|
+
|
5
|
+
# A Container for config keys
|
6
|
+
class KeyContainer
|
7
|
+
include TivoHMO::API::Container
|
8
|
+
include GemLogger::LoggerSupport
|
9
|
+
include MonitorMixin
|
10
|
+
|
11
|
+
def initialize(key)
|
12
|
+
super(key)
|
13
|
+
self.presorted = true
|
14
|
+
end
|
15
|
+
|
16
|
+
def children
|
17
|
+
synchronize do
|
18
|
+
if super.blank?
|
19
|
+
spec = Config.instance.known_config[identifier]
|
20
|
+
add_child(DisplayItem.new("Help", spec[:description]))
|
21
|
+
add_child(DisplayItem.new("Default Value: #{spec[:default_value]}"))
|
22
|
+
val = Config.instance.get(identifier)
|
23
|
+
add_child(DisplayItem.new("Current Value: #{!!val}"))
|
24
|
+
add_child(SetValueItem.new(identifier, !val))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module TivoHMO
|
2
|
+
module Adapters
|
3
|
+
module Settings
|
4
|
+
|
5
|
+
# Dummy metadata
|
6
|
+
class Metadata
|
7
|
+
include TivoHMO::API::Metadata
|
8
|
+
include GemLogger::LoggerSupport
|
9
|
+
|
10
|
+
attr_accessor :item_detail_callback
|
11
|
+
|
12
|
+
def initialize(item)
|
13
|
+
super(item)
|
14
|
+
end
|
15
|
+
|
16
|
+
# hack - star_rating only gets called when viewing item_detail
|
17
|
+
def star_rating
|
18
|
+
item_detail_callback.try(:call, self)
|
19
|
+
return nil
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'active_support/core_ext/string/inflections'
|
2
|
+
require 'listen'
|
3
|
+
|
4
|
+
module TivoHMO
|
5
|
+
module Adapters
|
6
|
+
module Settings
|
7
|
+
|
8
|
+
# An Item for toggling boolean bvalue
|
9
|
+
class ResetDefaultsItem
|
10
|
+
include TivoHMO::API::Item
|
11
|
+
include GemLogger::LoggerSupport
|
12
|
+
include MonitorMixin
|
13
|
+
|
14
|
+
def initialize()
|
15
|
+
super('reset_all')
|
16
|
+
self.title = "Reset Defaults"
|
17
|
+
end
|
18
|
+
|
19
|
+
def metadata
|
20
|
+
md = super
|
21
|
+
|
22
|
+
md.description = "All runtime config has now been reset to defaults, hit back to return"
|
23
|
+
|
24
|
+
md.item_detail_callback = Proc.new do
|
25
|
+
logger.info("Resetting defaults")
|
26
|
+
Config.instance.known_config.each do |key, spec|
|
27
|
+
Config.instance.set(key, spec[:default_value])
|
28
|
+
end
|
29
|
+
parent.children.clear
|
30
|
+
end
|
31
|
+
|
32
|
+
md
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'active_support/core_ext/string/inflections'
|
2
|
+
require 'listen'
|
3
|
+
|
4
|
+
module TivoHMO
|
5
|
+
module Adapters
|
6
|
+
module Settings
|
7
|
+
|
8
|
+
# An Item for toggling boolean bvalue
|
9
|
+
class SetValueItem
|
10
|
+
include TivoHMO::API::Item
|
11
|
+
include GemLogger::LoggerSupport
|
12
|
+
include MonitorMixin
|
13
|
+
|
14
|
+
def initialize(key, new_value)
|
15
|
+
super(key)
|
16
|
+
@new_value = new_value
|
17
|
+
self.title = "Set value to #{new_value}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def metadata
|
21
|
+
md = super
|
22
|
+
|
23
|
+
md.description = "Value has now been set to #{@new_value}, hit back to return"
|
24
|
+
|
25
|
+
md.item_detail_callback = Proc.new do
|
26
|
+
logger.info("Setting #{identifier} to: #{@new_value}")
|
27
|
+
Config.instance.set(identifier, @new_value)
|
28
|
+
parent.children.clear
|
29
|
+
end
|
30
|
+
|
31
|
+
md
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module TivoHMO
|
2
|
+
module Adapters
|
3
|
+
module Settings
|
4
|
+
|
5
|
+
|
6
|
+
# Dummy transcoder
|
7
|
+
class Transcoder
|
8
|
+
include TivoHMO::API::Transcoder
|
9
|
+
include GemLogger::LoggerSupport
|
10
|
+
|
11
|
+
def transcode(writeable_io, format="video/x-tivo-mpeg")
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def transcoder_options(format="video/x-tivo-mpeg")
|
16
|
+
{}
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
require_relative 'settings/transcoder'
|
2
|
+
require_relative 'settings/metadata'
|
3
|
+
require_relative 'settings/reset_defaults_item'
|
4
|
+
require_relative 'settings/set_value_item'
|
5
|
+
require_relative 'settings/display_item'
|
6
|
+
require_relative 'settings/key_container'
|
7
|
+
require_relative 'settings/application'
|
@@ -50,6 +50,7 @@ module TivoHMO
|
|
50
50
|
opts = select_audio_bitrate(opts)
|
51
51
|
opts = select_audio_sample_rate(opts)
|
52
52
|
opts = select_container(opts)
|
53
|
+
opts = select_subtitle(opts)
|
53
54
|
|
54
55
|
custom = opts.delete(:custom)
|
55
56
|
opts[:custom] = custom.join(" ") if custom
|
@@ -61,7 +62,7 @@ module TivoHMO
|
|
61
62
|
protected
|
62
63
|
|
63
64
|
def movie
|
64
|
-
@movie ||= FFMPEG::Movie.new(
|
65
|
+
@movie ||= FFMPEG::Movie.new(item.file)
|
65
66
|
end
|
66
67
|
|
67
68
|
def video_info
|
@@ -199,6 +200,43 @@ module TivoHMO
|
|
199
200
|
opts
|
200
201
|
end
|
201
202
|
|
203
|
+
def select_subtitle(opts)
|
204
|
+
|
205
|
+
st = item.subtitle
|
206
|
+
if st
|
207
|
+
case st.type
|
208
|
+
when :file
|
209
|
+
code = st.language_code
|
210
|
+
file = st.location
|
211
|
+
|
212
|
+
# TODO: This is a little hacky
|
213
|
+
# we have a leaky abstraction here but the file globbing is a bad
|
214
|
+
# performance hit to UI when generating Containers on first view
|
215
|
+
file_glob = file + ".*.srt"
|
216
|
+
sub_file = Dir[file_glob].find do |f|
|
217
|
+
file_code = f.split('.')[-2].downcase
|
218
|
+
file_code == code || file_code.starts_with?(code) || code.starts_with?(file_code)
|
219
|
+
end
|
220
|
+
|
221
|
+
if sub_file
|
222
|
+
logger.info "Using subtitles present at: #{sub_file}"
|
223
|
+
opts[:custom] << "-vf subtitles=\"#{sub_file}\""
|
224
|
+
else
|
225
|
+
logger.error "Subtitle doesn't exist at: #{file_glob}"
|
226
|
+
end
|
227
|
+
when :embedded
|
228
|
+
file = item.file
|
229
|
+
idx = st.location
|
230
|
+
logger.info "Using embedded subtitles [#{idx}] present at: #{file}"
|
231
|
+
opts[:custom] << "-vf subtitles=\"#{file}\":si=#{idx}"
|
232
|
+
else
|
233
|
+
logger.error "Unknown subtitle type: #{st.type}"
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
opts
|
238
|
+
end
|
239
|
+
|
202
240
|
def run_transcode(output_filename, format)
|
203
241
|
|
204
242
|
logger.info "Movie Info: " +
|
@@ -10,12 +10,13 @@ module TivoHMO
|
|
10
10
|
include Node
|
11
11
|
include GemLogger::LoggerSupport
|
12
12
|
|
13
|
-
attr_accessor :uuid
|
13
|
+
attr_accessor :uuid, :presorted
|
14
14
|
|
15
15
|
|
16
16
|
def initialize(identifier)
|
17
17
|
super(identifier)
|
18
18
|
self.uuid = SecureRandom.uuid
|
19
|
+
self.presorted = false
|
19
20
|
|
20
21
|
self.content_type = "x-tivo-container/tivo-videos"
|
21
22
|
self.source_format = "x-tivo-container/folder"
|
@@ -25,6 +26,9 @@ module TivoHMO
|
|
25
26
|
self.children = []
|
26
27
|
end
|
27
28
|
|
29
|
+
def child_count
|
30
|
+
children.size
|
31
|
+
end
|
28
32
|
end
|
29
33
|
|
30
34
|
end
|
data/lib/tivohmo/api/item.rb
CHANGED
@@ -17,12 +17,10 @@ module TivoHMO
|
|
17
17
|
AUDIO_CODECS = %w[ac3 liba52 mp2]
|
18
18
|
AUDIO_SAMPLE_RATES = %w[44100 48000]
|
19
19
|
|
20
|
-
attr_accessor :item
|
21
|
-
:source_filename
|
20
|
+
attr_accessor :item
|
22
21
|
|
23
22
|
def initialize(item)
|
24
23
|
self.item = item
|
25
|
-
self.source_filename = item.identifier
|
26
24
|
end
|
27
25
|
|
28
26
|
def transcode(writeable_io, format)
|
data/lib/tivohmo/api.rb
CHANGED
data/lib/tivohmo/beacon.rb
CHANGED
@@ -11,8 +11,6 @@ module TivoHMO
|
|
11
11
|
@interval = interval
|
12
12
|
@limit = limit
|
13
13
|
@uid = SecureRandom.uuid
|
14
|
-
@socket = UDPSocket.new(Socket::AF_INET)
|
15
|
-
@socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
|
16
14
|
@services = ['TiVoMediaServer:%s/http' % service_port]
|
17
15
|
@running = false
|
18
16
|
end
|
@@ -66,7 +64,9 @@ module TivoHMO
|
|
66
64
|
bcast_port = 2190
|
67
65
|
packet = beacon_data('broadcast')
|
68
66
|
logger.debug "Sending beacon packet: #{packet}"
|
69
|
-
|
67
|
+
socket = UDPSocket.new(Socket::AF_INET)
|
68
|
+
socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
|
69
|
+
socket.send(packet, 0, bcast_ip, bcast_port)
|
70
70
|
end
|
71
71
|
|
72
72
|
end
|
data/lib/tivohmo/cli.rb
CHANGED
@@ -22,18 +22,26 @@ module TivoHMO
|
|
22
22
|
|
23
23
|
e.g.
|
24
24
|
|
25
|
-
tivohmo -
|
26
|
-
|
25
|
+
tivohmo -t Movies
|
26
|
+
-a TivoHMO::Adapters::Filesystem::Application \\
|
27
|
+
-i ~/Video/Movies \\
|
28
|
+
-t "TV Shows" \\
|
29
|
+
-a TivoHMO::Adapters::Filesystem::Application \\
|
30
|
+
-i ~/Video/TV
|
27
31
|
|
28
32
|
to run two top level filesystem video serving apps for different dirs, or
|
29
33
|
|
30
|
-
tivohmo -
|
34
|
+
tivohmo -t Vids \\
|
35
|
+
-a TivoHMO::Adapters::Filesystem::Application \\
|
36
|
+
-i ~/Video
|
31
37
|
|
32
|
-
to run the single filesystem app
|
38
|
+
to run the single filesystem app, or
|
33
39
|
|
34
|
-
tivohmo -
|
40
|
+
tivohmo -t PlexVideo \\
|
41
|
+
-a TivoHMO::Adapters::Plex::Application \\
|
42
|
+
-i localhost
|
35
43
|
|
36
|
-
to run the single plex app
|
44
|
+
to run the single plex app
|
37
45
|
DESC
|
38
46
|
desc.split("\n").collect(&:strip).join("\n")
|
39
47
|
end
|
@@ -62,6 +70,13 @@ module TivoHMO
|
|
62
70
|
option ["-f", "--configuration"],
|
63
71
|
"FILE", "load configuration from given filename\n"
|
64
72
|
|
73
|
+
option ["-s", "--settings"],
|
74
|
+
"FILE", "a writable file for storing runtime settings\n"
|
75
|
+
|
76
|
+
option ["-t", "--title"],
|
77
|
+
"TITLE", "setup an application for the given title\n",
|
78
|
+
multivalued: true
|
79
|
+
|
65
80
|
option ["-a", "--application"],
|
66
81
|
"CLASSNAME", "use the given application class\n",
|
67
82
|
multivalued: true
|
@@ -71,10 +86,6 @@ module TivoHMO
|
|
71
86
|
"a string that has meaning to the application\n",
|
72
87
|
multivalued: true
|
73
88
|
|
74
|
-
option ["-t", "--title"],
|
75
|
-
"TITLE", "use the given title for the application\n",
|
76
|
-
multivalued: true
|
77
|
-
|
78
89
|
option ["-T", "--transcoder"],
|
79
90
|
"CLASSNAME", "override the application's transcoder class\n",
|
80
91
|
multivalued: true
|
@@ -86,59 +97,37 @@ module TivoHMO
|
|
86
97
|
option ["-b", "--beacon"],
|
87
98
|
"LIMIT:INTERVAL", "configure beacon limit and/or interval\n"
|
88
99
|
|
100
|
+
option ["-l", "--install"],
|
101
|
+
:flag, "install tivohmo into your system\n"
|
102
|
+
|
89
103
|
def execute
|
104
|
+
|
90
105
|
if version?
|
91
106
|
puts "TivoHMO Version #{TivoHMO::VERSION}"
|
92
107
|
return
|
93
108
|
end
|
94
109
|
|
95
|
-
|
96
|
-
|
97
|
-
logger.info "TivoHMO #{TivoHMO::VERSION} starting up"
|
110
|
+
install_tivohmo if install?
|
98
111
|
|
99
|
-
if configuration
|
100
|
-
|
112
|
+
c = File.expand_path(configuration) if configuration
|
113
|
+
s = File.expand_path(settings) if settings
|
114
|
+
TivoHMO::Config.instance.setup(c, s)
|
101
115
|
|
102
|
-
|
103
|
-
set_if_default(:port, config['port'].to_i)
|
104
|
-
end
|
116
|
+
setup_logging
|
105
117
|
|
106
|
-
|
107
|
-
signal_usage_error "an initializer is needed for each application" unless
|
108
|
-
application_list.size == identifier_list.size
|
118
|
+
logger.info "TivoHMO #{TivoHMO::VERSION} starting up"
|
109
119
|
|
110
|
-
|
111
|
-
|
112
|
-
path = c.downcase.split('::')[0..-2].join('/')
|
113
|
-
require path
|
114
|
-
end
|
115
|
-
end
|
120
|
+
# allow cli option to override config file
|
121
|
+
set_if_default(:port, TivoHMO::Config.instance.get(:port).try(:to_i))
|
116
122
|
|
117
123
|
server = TivoHMO::API::Server.new
|
118
|
-
|
119
|
-
|
120
|
-
title_list,
|
121
|
-
transcoder_list,
|
122
|
-
metadata_list)
|
123
|
-
|
124
|
-
apps_with_config.each do |app_classname, identifier, title, transcoder, metadata|
|
125
|
-
app_class = app_classname.constantize
|
126
|
-
app = app_class.new(identifier)
|
127
|
-
|
128
|
-
if title
|
129
|
-
app.title = title
|
130
|
-
else
|
131
|
-
app.title = "#{app.title} on #{server.title}"
|
132
|
-
end
|
133
|
-
|
134
|
-
app.transcoder_class = transcoder.constantize if transcoder
|
135
|
-
app.metadata_class = metadata.constantize if metadata
|
136
|
-
server.add_child(app)
|
137
|
-
end
|
124
|
+
apps = setup_applications
|
125
|
+
apps.each {|app| server.add_child(app) }
|
138
126
|
|
139
127
|
preload_containers(server) if preload?
|
140
128
|
|
141
129
|
opts = {}
|
130
|
+
set_if_default(:beacon, TivoHMO::Config.instance.get(:beacon))
|
142
131
|
if beacon.present?
|
143
132
|
limit, interval = beacon.split(":")
|
144
133
|
opts[:limit] = limit.to_i if limit.present?
|
@@ -154,8 +143,10 @@ module TivoHMO
|
|
154
143
|
private
|
155
144
|
|
156
145
|
def setup_logging
|
146
|
+
set_if_default(:debug, TivoHMO::Config.instance.get(:debug))
|
157
147
|
Logging.logger.root.level = :debug if debug?
|
158
148
|
|
149
|
+
set_if_default(:logfile, TivoHMO::Config.instance.get(:logfile))
|
159
150
|
if logfile.present?
|
160
151
|
appender = Logging.appenders.rolling_file(
|
161
152
|
logfile,
|
@@ -176,7 +167,64 @@ module TivoHMO
|
|
176
167
|
end
|
177
168
|
|
178
169
|
def set_if_default(attr, new_value)
|
179
|
-
|
170
|
+
opt = self.class.find_option("--#{attr}")
|
171
|
+
raise "Unknonwn cli attribute" unless opt
|
172
|
+
self.send("#{attr}=", new_value) if new_value && self.send(opt.read_method) == opt.default_value
|
173
|
+
end
|
174
|
+
|
175
|
+
def load_adapter(clazz)
|
176
|
+
if clazz && clazz.starts_with?('TivoHMO::Adapters::')
|
177
|
+
path = clazz.downcase.split('::')[0..-2].join('/')
|
178
|
+
require path
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def setup_applications
|
183
|
+
app_specs = TivoHMO::Config.instance.get(:applications) || {}
|
184
|
+
|
185
|
+
title_list.each_with_index do |title, i|
|
186
|
+
app = app_specs[title]
|
187
|
+
app_was_in_config = app.present?
|
188
|
+
app = {} unless app_was_in_config
|
189
|
+
|
190
|
+
app[:application] = application_list[i] if application_list[i]
|
191
|
+
signal_usage_error "an application class is needed for each application" unless app[:application]
|
192
|
+
|
193
|
+
app[:identifier] = identifier_list[i] if identifier_list[i]
|
194
|
+
signal_usage_error "an initializer is needed for each application" unless app[:identifier]
|
195
|
+
|
196
|
+
|
197
|
+
app[:transcoder] = transcoder_list[i] if transcoder_list[i]
|
198
|
+
app[:metadata] = metadata_list[i] if metadata_list[i]
|
199
|
+
|
200
|
+
logger.debug "Merged app: #{title} - #{app.inspect}"
|
201
|
+
app_specs[title] = app unless app_was_in_config
|
202
|
+
end
|
203
|
+
|
204
|
+
signal_usage_error "at least one application is required" unless app_specs.present?
|
205
|
+
|
206
|
+
apps = app_specs.collect do |title, app_spec|
|
207
|
+
logger.debug "Adding app: #{title} - #{app_spec.inspect}"
|
208
|
+
load_adapter(app_spec[:application])
|
209
|
+
|
210
|
+
app_class = app_spec[:application].constantize
|
211
|
+
app = app_class.new(app_spec[:identifier])
|
212
|
+
app.title = title
|
213
|
+
|
214
|
+
if app_spec[:transcoder]
|
215
|
+
load_adapter(app_spec[:transcoder])
|
216
|
+
app.transcoder_class = app_spec[:transcoder].constantize
|
217
|
+
end
|
218
|
+
|
219
|
+
if app_spec[:metadata]
|
220
|
+
load_adapter(app_spec[:metadata])
|
221
|
+
app.metadata_class = app_spec[:metadata].constantize
|
222
|
+
end
|
223
|
+
|
224
|
+
app
|
225
|
+
end
|
226
|
+
|
227
|
+
apps
|
180
228
|
end
|
181
229
|
|
182
230
|
def preload_containers(server)
|
@@ -204,6 +252,85 @@ module TivoHMO
|
|
204
252
|
end
|
205
253
|
end
|
206
254
|
|
255
|
+
# Opens the file for writing by root
|
256
|
+
def sudo_open(path, mode, perms=0755, &block)
|
257
|
+
open("|sudo tee #{path} > /dev/null", perms, &block)
|
258
|
+
end
|
259
|
+
|
260
|
+
def get_binding(config)
|
261
|
+
binding
|
262
|
+
end
|
263
|
+
|
264
|
+
def install_file(src, dst, config={}, sudo=false)
|
265
|
+
src = File.expand_path(src)
|
266
|
+
dst = File.expand_path(dst)
|
267
|
+
|
268
|
+
block = Proc.new do |f|
|
269
|
+
template = ERB.new(File.read(src), nil, "-")
|
270
|
+
result = template.result(get_binding(config))
|
271
|
+
f.write(result)
|
272
|
+
end
|
273
|
+
|
274
|
+
puts "Installing #{dst}"
|
275
|
+
|
276
|
+
if sudo
|
277
|
+
sudo_open(dst, "w", &block)
|
278
|
+
else
|
279
|
+
open(dst, "w", &block)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def install_tivohmo
|
284
|
+
puts "Installing TivoHMO"
|
285
|
+
|
286
|
+
contrib_path = File.expand_path("../../../contrib", __FILE__)
|
287
|
+
|
288
|
+
case RUBY_PLATFORM
|
289
|
+
when /darwin/
|
290
|
+
|
291
|
+
config = {
|
292
|
+
daemon_config: "~/Library/LaunchAgents/tivohmo.plist",
|
293
|
+
configuration: "~/Library/Preferences/tivohmo.yml",
|
294
|
+
logfile: "~/Library/Logs/tivohmo.log",
|
295
|
+
settings: "~/Library/Preferences/tivohmo.runtime.yml"
|
296
|
+
}
|
297
|
+
|
298
|
+
install_file("#{contrib_path}/tivohmo.yml", config[:configuration], config)
|
299
|
+
install_file("#{contrib_path}/tivohmo.plist", config[:daemon_config], config)
|
300
|
+
|
301
|
+
puts "TivoHMO installed"
|
302
|
+
puts "To start tivohmo, execute the command:"
|
303
|
+
puts "\tlaunchctl load #{config[:daemon_config]}"
|
304
|
+
puts "To stop tivohmo, execute the command:"
|
305
|
+
puts "\tlaunchctl unload #{config[:daemon_config]}"
|
306
|
+
|
307
|
+
when /linux/
|
308
|
+
|
309
|
+
config = {
|
310
|
+
daemon_config: "/etc/init/tivohmo.conf",
|
311
|
+
configuration: "/etc/tivohmo.yml",
|
312
|
+
logfile: "/var/log/tivohmo.log",
|
313
|
+
settings: "/var/run/tivohmo.runtime.yml"
|
314
|
+
}
|
315
|
+
|
316
|
+
puts "Sudo password needed to install files"
|
317
|
+
install_file("#{contrib_path}/tivohmo.yml", config[:configuration], config, true)
|
318
|
+
install_file("#{contrib_path}/tivohmo.conf", config[:daemon_config], config, true)
|
319
|
+
|
320
|
+
puts "TivoHMO installed"
|
321
|
+
puts "To start tivohmo, execute the command:"
|
322
|
+
puts "\tsudo service tivohmo start"
|
323
|
+
puts "To stop tivohmo, execute the command:"
|
324
|
+
puts "\tsudo service tivohmo stop"
|
325
|
+
|
326
|
+
else
|
327
|
+
$stderr.puts "Unsupported OS: #{RUBY_PLATFORM}"
|
328
|
+
exit(1)
|
329
|
+
end
|
330
|
+
|
331
|
+
exit(0)
|
332
|
+
end
|
333
|
+
|
207
334
|
end
|
208
335
|
|
209
336
|
end
|