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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf38e58ce80df9b5a177019960ace75cee1214cd
|
4
|
+
data.tar.gz: 84358dcbc8cc552c560a34b67cd3bec1f40d7d62
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1643360b023aa69207324541bfd041b25ce3d07e7211aa57bc7a3b33ab6b497c6063a560ba26ebe0f577e18a4fc8361838de7778b5758b5250b06f59996e62be
|
7
|
+
data.tar.gz: 807c936f1152bb55a0a62ddcb6c933aaa0c03d19c44cf407fde517f283ca16c8e3ccb6fb2d84744090f3cb90885077fbde392fc831ac75540d59ab85af34fee0
|
data/.travis.yml
CHANGED
data/CHANGELOG
CHANGED
@@ -1,3 +1,33 @@
|
|
1
|
+
0.3.0 (03/01/2015)
|
2
|
+
------------------
|
3
|
+
|
4
|
+
Use a group for subtitles+original <a552478> [Matt Conway]
|
5
|
+
add ability to optionally hardcode subtitles when present <df079f8> [Matt Conway]
|
6
|
+
add ability to skip sorting by setting presorted flag <5148bcf> [Matt Conway]
|
7
|
+
add reset to defaults <71f12ce> [Matt Conway]
|
8
|
+
add settings mechanism and app to control it from tivo ui <8fce56c> [Matt Conway]
|
9
|
+
add todo <e7b0f6b> [Matt Conway]
|
10
|
+
allow implementations to not have to load children to show a count <40464c6> [Matt Conway]
|
11
|
+
allow reading cli config from file <f208616> [Matt Conway]
|
12
|
+
allow video fixture with vcr <09a792e> [Matt Conway]
|
13
|
+
app for changing runtime settings <4f1cd05> [Matt Conway]
|
14
|
+
beacon seems to work better on linux if I create a new socket for each broadcast <879573a> [Matt Conway]
|
15
|
+
better title for subs <1755a82> [Matt Conway]
|
16
|
+
change ffmpeg ppa <11c96c0> [Matt Conway]
|
17
|
+
cli install templates <e9ec91f> [Matt Conway]
|
18
|
+
config tests <0c3b23e> [Matt Conway]
|
19
|
+
config working <57f7fc8> [Matt Conway]
|
20
|
+
fix performance issue with subtitles, allow for embedded subtitles (e.g. mkv) <6da6aa3> [Matt Conway]
|
21
|
+
fix plex cache updating <5f45b69> [Matt Conway]
|
22
|
+
more metadata <8608b5c> [Matt Conway]
|
23
|
+
move webmock to gemfile to prevent auto require <3f19631> [Matt Conway]
|
24
|
+
new vcr fixtures <1dfa166> [Matt Conway]
|
25
|
+
partial <951dada> [Matt Conway]
|
26
|
+
redo plex tests with vcr <5da4030> [Matt Conway]
|
27
|
+
refactor to make item have a file, refactor subtitles and transcoding, misc tests <70a8f37> [Matt Conway]
|
28
|
+
update readme <2338cff> [Matt Conway]
|
29
|
+
work with rvm <ecff585> [Matt Conway]
|
30
|
+
|
1
31
|
0.2.3 (11/29/2014)
|
2
32
|
------------------
|
3
33
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -21,14 +21,11 @@ Install the gem:
|
|
21
21
|
|
22
22
|
$ gem install tivohmo
|
23
23
|
|
24
|
-
|
24
|
+
then install as a daemon with default configuration:
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
And then execute:
|
29
|
-
|
30
|
-
$ bundle
|
26
|
+
$ tivohmo --install
|
31
27
|
|
28
|
+
Optionally edit the installed configuration file mentioned when the install command executes, and restart the daemon.
|
32
29
|
|
33
30
|
## Usage
|
34
31
|
|
@@ -36,6 +33,7 @@ Run the 'tivohmo' binary for usage:
|
|
36
33
|
|
37
34
|
tivohmo --help
|
38
35
|
|
36
|
+
|
39
37
|
## Developing
|
40
38
|
|
41
39
|
Use the classes in TivoHMO::API to create your tree of data (Application -> Container(s) -> Items), then serve them with TivoHMO::Server. See TivoHMO::Adapters::Filesystem for a sample implementation based on folders/files/ffmpeg
|
data/contrib/tivohmo.conf
CHANGED
@@ -9,7 +9,7 @@ stop on runlevel [!2345]
|
|
9
9
|
|
10
10
|
respawn
|
11
11
|
respawn limit 10 5
|
12
|
-
setuid
|
12
|
+
setuid root
|
13
13
|
umask 022
|
14
14
|
|
15
|
-
exec
|
15
|
+
exec bash -l -c "tivohmo --configuration /etc/tivohmo.yml"
|
data/contrib/tivohmo.plist
CHANGED
@@ -16,7 +16,7 @@ Then to start the server, run: launchctl load ~/Library/LaunchAgents/tivohmo.pli
|
|
16
16
|
<string>bash</string>
|
17
17
|
<string>-l</string>
|
18
18
|
<string>-c</string>
|
19
|
-
<string>tivohmo
|
19
|
+
<string>tivohmo --configuration <%= File.expand_path(config[:configuration]) %></string>
|
20
20
|
</array>
|
21
21
|
<key>RunAtLoad</key>
|
22
22
|
<true/>
|
data/contrib/tivohmo.yml
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# The network port to listen to tivo requests on
|
2
|
+
port: 9033
|
3
|
+
|
4
|
+
# Run with debug logging enabled
|
5
|
+
debug: false
|
6
|
+
|
7
|
+
# Walk the application trees to preload all data for quicker browsing at
|
8
|
+
# the expense of slower startup
|
9
|
+
preload: false
|
10
|
+
|
11
|
+
# The file to record tivohmo logs in
|
12
|
+
logfile: <%= config[:logfile] %>
|
13
|
+
|
14
|
+
# The runtime settings file for saving config changes made using the
|
15
|
+
# Settings app. Must be writable by the tivohmo process
|
16
|
+
settings: <%= config[:settings] %>
|
17
|
+
|
18
|
+
# The limit:interval for broadcasting beacon signals to the network
|
19
|
+
# -1 as the limit means infinite
|
20
|
+
beacon: "-1:10"
|
21
|
+
|
22
|
+
# The applications to enable
|
23
|
+
applications:
|
24
|
+
# The Settings app for editing runtime changeable settings
|
25
|
+
TivoHMO Settings:
|
26
|
+
application: TivoHMO::Adapters::Settings::Application
|
27
|
+
identifier: settings
|
28
|
+
# The Plex app for sharing video from a plex media server. This currently
|
29
|
+
# only works if the plex server is running on the same host as tivohmo
|
30
|
+
TivoHMO Plex Videos:
|
31
|
+
application: TivoHMO::Adapters::Plex::Application
|
32
|
+
identifier: localhost
|
33
|
+
# # The filesystem app for sharing video from a directory
|
34
|
+
# TivoHMO Filesystem Videos:
|
35
|
+
# application: TivoHMO::Adapters::Filesystem::Application
|
36
|
+
# identifier: /My/Video
|
37
|
+
|
38
|
+
|
39
|
+
# BEGIN RUNTIME EDITABLE SETTINGS
|
40
|
+
#
|
41
|
+
|
42
|
+
# These settings are all editable from the TivoHMO Settings app, and will
|
43
|
+
# get saved to the file specified in the 'settings' config above, thereby
|
44
|
+
# overriding any settings configured below.
|
45
|
+
|
46
|
+
# Detect subtitles for videos and include them as a choice when browsing
|
47
|
+
# Runtime editable from Settings app
|
48
|
+
enable_subtitles: true
|
49
|
+
|
50
|
+
# Force groups/folders regardless of parameters supplied by the tivo request
|
51
|
+
# Runtime editable from Settings app
|
52
|
+
force_grouping: true
|
53
|
+
|
54
|
+
# Use zap2it ID for grouping episodes (Gives thumbnail in My Shows, but can
|
55
|
+
# cause problems)
|
56
|
+
# Runtime editable from Settings app
|
57
|
+
group_with_zap2it: true
|
58
|
+
|
59
|
+
#
|
60
|
+
# END RUNTIME EDITABLE SETTINGS
|
@@ -9,14 +9,13 @@ module TivoHMO
|
|
9
9
|
include TivoHMO::API::Item
|
10
10
|
include GemLogger::LoggerSupport
|
11
11
|
|
12
|
-
attr_reader :full_path
|
13
|
-
|
14
12
|
def initialize(identifier)
|
15
|
-
|
13
|
+
full_path = File.expand_path(identifier)
|
16
14
|
raise ArgumentError, "Must provide an existing file" unless File.file?(full_path)
|
17
15
|
|
18
16
|
super(full_path)
|
19
17
|
|
18
|
+
self.file = full_path
|
20
19
|
self.title = File.basename(self.identifier)
|
21
20
|
self.modified_at = File.mtime(self.identifier)
|
22
21
|
self.created_at = File.ctime(self.identifier)
|
@@ -6,15 +6,20 @@ module TivoHMO
|
|
6
6
|
include TivoHMO::API::Container
|
7
7
|
include GemLogger::LoggerSupport
|
8
8
|
include MonitorMixin
|
9
|
+
include TivoHMO::Config::Mixin
|
9
10
|
|
10
11
|
attr_reader :delegate
|
11
12
|
attr_accessor :category_type, :category_value
|
12
13
|
|
13
|
-
|
14
|
+
config_register(:enable_subtitles, true,
|
15
|
+
"For items that have subtitles, adds entries that will transcode with those subtitles hardcoded")
|
16
|
+
|
17
|
+
def initialize(delegate, category_type, category_value=nil, presorted=false)
|
14
18
|
# delegate is a Plex::Section
|
15
19
|
@delegate = delegate
|
16
20
|
|
17
21
|
super(delegate.key)
|
22
|
+
self.presorted = presorted
|
18
23
|
|
19
24
|
self.category_type = category_type
|
20
25
|
self.category_value = category_value
|
@@ -27,20 +32,33 @@ module TivoHMO
|
|
27
32
|
|
28
33
|
self.modified_at = Time.at(delegate.updated_at.to_i)
|
29
34
|
self.created_at = Time.now
|
35
|
+
@subtitles = config_get(:enable_subtitles)
|
36
|
+
end
|
37
|
+
|
38
|
+
alias_method :super_children, :children
|
39
|
+
|
40
|
+
def child_count
|
41
|
+
super_children.size
|
30
42
|
end
|
31
43
|
|
32
44
|
def children
|
33
45
|
synchronize do
|
34
46
|
|
35
|
-
|
36
|
-
|
47
|
+
# updated_at doesn't get updated for automatic updates, only
|
48
|
+
# for updating from within plex media server web ui
|
49
|
+
section_id = delegate.key.split('/').last
|
50
|
+
new_delegate = delegate.library.section!(section_id)
|
51
|
+
new_modified_at = new_delegate.updated_at.to_i
|
37
52
|
if new_modified_at > modified_at.to_i
|
38
53
|
logger.info "Plex section was updated, refreshing"
|
54
|
+
@delegate = new_delegate
|
39
55
|
self.modified_at = Time.at(new_modified_at)
|
40
56
|
super.clear
|
41
57
|
end
|
42
58
|
|
43
|
-
if super.blank?
|
59
|
+
if super.blank? || @subtitles != config_get(:enable_subtitles)
|
60
|
+
super.clear
|
61
|
+
@subtitles = config_get(:enable_subtitles)
|
44
62
|
|
45
63
|
if category_value
|
46
64
|
listing = delegate.send(category_type, category_value[:key])
|
@@ -50,9 +68,9 @@ module TivoHMO
|
|
50
68
|
|
51
69
|
Array(listing).each do |media|
|
52
70
|
if media.is_a?(::Plex::Movie)
|
53
|
-
|
71
|
+
add_grouped(Movie, media)
|
54
72
|
elsif media.is_a?(::Plex::Episode)
|
55
|
-
|
73
|
+
add_grouped(Episode, media)
|
56
74
|
elsif media.is_a?(::Plex::Show)
|
57
75
|
add_child(Show.new(media))
|
58
76
|
else
|
@@ -65,6 +83,69 @@ module TivoHMO
|
|
65
83
|
super
|
66
84
|
end
|
67
85
|
|
86
|
+
def add_grouped(item_class, item_delegate)
|
87
|
+
primary = item_class.new(item_delegate)
|
88
|
+
|
89
|
+
if config_get(:enable_subtitles)
|
90
|
+
subs = find_subtitles(item_delegate)
|
91
|
+
|
92
|
+
if subs.size > 0
|
93
|
+
group = Group.new(primary.identifier, primary.title)
|
94
|
+
add_child(group)
|
95
|
+
group.add_child(primary)
|
96
|
+
subs.each {|s| group.add_child(item_class.new(item_delegate, s)) }
|
97
|
+
else
|
98
|
+
add_child(primary)
|
99
|
+
end
|
100
|
+
else
|
101
|
+
add_child(primary)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def find_subtitles(item_delegate)
|
106
|
+
subs = []
|
107
|
+
|
108
|
+
source_filename = CGI.unescape(item_delegate.medias.first.parts.first.file)
|
109
|
+
|
110
|
+
item_delegate.medias.each do |media|
|
111
|
+
media.parts.each do |part|
|
112
|
+
prev_stream_count = 0
|
113
|
+
part.streams.each do |stream|
|
114
|
+
|
115
|
+
# stream.stream_type 3=subs, 1=video, 2=audio
|
116
|
+
# stream.key.present? means file based srt
|
117
|
+
# stream.index and no key, means embedded
|
118
|
+
if stream.stream_type.to_i == 3
|
119
|
+
if %w[key language language_code].all? {|m| stream.respond_to?(m) && stream.send(m).present? }
|
120
|
+
st = TivoHMO::API::Subtitle.new
|
121
|
+
st.language = stream.language
|
122
|
+
st.language_code = stream.language_code
|
123
|
+
st.format = stream.codec
|
124
|
+
st.type = :file
|
125
|
+
st.location = source_filename.chomp(File.extname(source_filename))
|
126
|
+
subs << st
|
127
|
+
elsif stream.respond_to?(:index) && stream.index.present?
|
128
|
+
st = TivoHMO::API::Subtitle.new
|
129
|
+
st.language = stream.respond_to?(:language) && stream.language || "Embedded"
|
130
|
+
st.language_code = stream.respond_to?(:language_code) && stream.language_code || "???"
|
131
|
+
st.format = stream.codec
|
132
|
+
st.type = :embedded
|
133
|
+
# subtitle index should be the index amongst just the embedded subtitle streams
|
134
|
+
st.location = stream.index.to_i - prev_stream_count
|
135
|
+
subs << st
|
136
|
+
else
|
137
|
+
logger.warn "Unrecognized subtitle for #{item_delegate.title}"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
prev_stream_count += 1
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
subs
|
147
|
+
end
|
148
|
+
|
68
149
|
end
|
69
150
|
|
70
151
|
end
|
@@ -7,16 +7,25 @@ module TivoHMO
|
|
7
7
|
class Episode
|
8
8
|
include TivoHMO::API::Item
|
9
9
|
include GemLogger::LoggerSupport
|
10
|
+
include TivoHMO::Config::Mixin
|
10
11
|
|
11
|
-
attr_reader :delegate
|
12
|
+
attr_reader :delegate, :subtitle
|
12
13
|
|
13
|
-
|
14
|
+
config_register(:group_with_zap2it, true,
|
15
|
+
"Use zap2it ID for grouping episodes (Gives thumbnail in My Shows, but can cause problems)")
|
16
|
+
|
17
|
+
def initialize(delegate, subtitle=nil)
|
14
18
|
# delegate is a Plex::Episode
|
15
19
|
@delegate = delegate
|
16
20
|
|
17
21
|
super(delegate.key)
|
18
22
|
|
23
|
+
self.file = CGI.unescape(delegate.medias.first.parts.first.file)
|
24
|
+
self.subtitle = subtitle
|
25
|
+
|
19
26
|
self.title = delegate.title
|
27
|
+
self.title = "[#{subtitle.language_code} sub] #{self.title}" if subtitle
|
28
|
+
|
20
29
|
self.modified_at = Time.at(delegate.updated_at.to_i)
|
21
30
|
self.created_at = Time.parse(delegate.originally_available_at) rescue nil
|
22
31
|
self.created_at ||= Time.at(delegate.added_at.to_i)
|
@@ -29,7 +38,7 @@ module TivoHMO
|
|
29
38
|
|
30
39
|
md.original_air_date = Time.parse(delegate.originally_available_at) rescue nil
|
31
40
|
|
32
|
-
rating_name = delegate.content_rating.upcase
|
41
|
+
rating_name = delegate.content_rating.upcase rescue nil
|
33
42
|
rating_value = TivoHMO::API::Metadata::TV_RATINGS[rating_name]
|
34
43
|
if rating_value
|
35
44
|
md.tv_rating = {name: rating_name, value: rating_value}
|
@@ -43,6 +52,13 @@ module TivoHMO
|
|
43
52
|
|
44
53
|
md.series_id = lookup_series_id
|
45
54
|
|
55
|
+
md.actors = delegate.roles.collect(&:tag) rescue nil
|
56
|
+
md.series_genres = delegate.genres.collect(&:tag) rescue nil
|
57
|
+
|
58
|
+
%w[writers directors producers].each do |md_name|
|
59
|
+
md.send("#{md_name}=", delegate.send(md_name).collect(&:tag)) rescue nil
|
60
|
+
end
|
61
|
+
|
46
62
|
rescue => e
|
47
63
|
logger.log_exception e, "Failed to read plex metadata for #{self}"
|
48
64
|
end
|
@@ -52,20 +68,23 @@ module TivoHMO
|
|
52
68
|
|
53
69
|
# groups tv shows under same name if we can extract a seriesId
|
54
70
|
def lookup_series_id
|
55
|
-
series_id =
|
71
|
+
series_id = "SH%08i" % delegate.season.show.key.scan(/\d+/).first.to_i
|
56
72
|
|
57
73
|
guid = delegate.guid
|
58
74
|
if guid =~ /thetvdb:\/\/(\d+)/
|
59
75
|
# zap2it ids allow tivo to show a relevant thumbnail image for the
|
60
76
|
# series in the My Shows UI.
|
61
77
|
tvdb_series_id = $1
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
78
|
+
|
79
|
+
if config_get(:group_with_zap2it)
|
80
|
+
begin
|
81
|
+
tvdb_series = TVDBHelper.instance.find_by_id(tvdb_series_id)
|
82
|
+
series_id = tvdb_series.zap2it_id
|
83
|
+
series_id = series_id.sub(/^EP/, 'SH')
|
84
|
+
logger.debug "Using zap2it series id: #{series_id}"
|
85
|
+
rescue => e
|
86
|
+
logger.log_exception e, "Failed to get zap2it series id", level: :warn
|
87
|
+
end
|
69
88
|
end
|
70
89
|
|
71
90
|
series_id ||= "SH#{tvdb_series_id}"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module TivoHMO
|
2
|
+
module Adapters
|
3
|
+
module Plex
|
4
|
+
|
5
|
+
class Group
|
6
|
+
include TivoHMO::API::Container
|
7
|
+
include GemLogger::LoggerSupport
|
8
|
+
|
9
|
+
def initialize(ident, title)
|
10
|
+
super(ident)
|
11
|
+
|
12
|
+
self.presorted = true
|
13
|
+
self.title = title
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -6,15 +6,20 @@ module TivoHMO
|
|
6
6
|
include TivoHMO::API::Item
|
7
7
|
include GemLogger::LoggerSupport
|
8
8
|
|
9
|
-
attr_reader :delegate
|
9
|
+
attr_reader :delegate, :subtitle
|
10
10
|
|
11
|
-
def initialize(delegate)
|
11
|
+
def initialize(delegate, subtitle=nil)
|
12
12
|
# delegate is a Plex::Movie
|
13
13
|
@delegate = delegate
|
14
14
|
|
15
15
|
super(delegate.key)
|
16
16
|
|
17
|
+
self.file = CGI.unescape(delegate.medias.first.parts.first.file)
|
18
|
+
self.subtitle = subtitle
|
19
|
+
|
17
20
|
self.title = delegate.title
|
21
|
+
self.title = "[#{subtitle.language_code} sub] #{self.title}" if subtitle
|
22
|
+
|
18
23
|
self.modified_at = Time.at(delegate.updated_at.to_i)
|
19
24
|
self.created_at = Time.parse(delegate.originally_available_at) rescue nil
|
20
25
|
self.created_at ||= Time.at(delegate.added_at.to_i)
|
@@ -27,12 +32,19 @@ module TivoHMO
|
|
27
32
|
|
28
33
|
md.movie_year = Time.parse(delegate.originally_available_at).year rescue nil
|
29
34
|
|
30
|
-
rating_name = delegate.content_rating.upcase
|
35
|
+
rating_name = delegate.content_rating.upcase rescue nil
|
31
36
|
rating_value = TivoHMO::API::Metadata::MPAA_RATINGS[rating_name]
|
32
37
|
if rating_value
|
33
38
|
md.mpaa_rating = {name: rating_name, value: rating_value}
|
34
39
|
end
|
35
40
|
|
41
|
+
md.actors = delegate.roles.collect(&:tag) rescue nil
|
42
|
+
md.program_genres = delegate.genres.collect(&:tag) rescue nil
|
43
|
+
|
44
|
+
%w[writers directors producers].each do |md_name|
|
45
|
+
md.send("#{md_name}=", delegate.send(md_name).collect(&:tag)) rescue nil
|
46
|
+
end
|
47
|
+
|
36
48
|
rescue => e
|
37
49
|
logger.log_exception e, "Failed to read plex metadata for #{self}"
|
38
50
|
end
|
@@ -15,6 +15,7 @@ module TivoHMO
|
|
15
15
|
@delegate = delegate
|
16
16
|
|
17
17
|
super(delegate.key)
|
18
|
+
self.presorted = true
|
18
19
|
|
19
20
|
self.category_type = category_type
|
20
21
|
self.category_qualifier = category_qualifier
|
@@ -23,13 +24,23 @@ module TivoHMO
|
|
23
24
|
self.created_at = Time.now
|
24
25
|
end
|
25
26
|
|
27
|
+
alias_method :super_children, :children
|
28
|
+
|
29
|
+
def child_count
|
30
|
+
super_children.size
|
31
|
+
end
|
32
|
+
|
26
33
|
def children
|
27
34
|
synchronize do
|
28
35
|
|
29
|
-
|
30
|
-
|
36
|
+
# updated_at doesn't get updated for automatic updates, only
|
37
|
+
# for updating from within plex media server web ui
|
38
|
+
section_id = delegate.key.split('/').last
|
39
|
+
new_delegate = delegate.library.section!(section_id)
|
40
|
+
new_modified_at = new_delegate.updated_at.to_i
|
31
41
|
if new_modified_at > modified_at.to_i
|
32
42
|
logger.info "Plex section was updated, refreshing"
|
43
|
+
@delegate = new_delegate
|
33
44
|
self.modified_at = Time.at(new_modified_at)
|
34
45
|
super.clear
|
35
46
|
end
|
@@ -39,7 +50,7 @@ module TivoHMO
|
|
39
50
|
# Sort by title descending so that creation times are
|
40
51
|
# correct for tivo sort of newest first (Time.now for
|
41
52
|
# created_at in Category)
|
42
|
-
qualified = qualified.sort_by{|c| c[:title] }
|
53
|
+
qualified = qualified.sort_by{|c| c[:title] }
|
43
54
|
qualified.each do |category_value|
|
44
55
|
add_child(Category.new(delegate, category_type, category_value))
|
45
56
|
end
|
@@ -16,8 +16,8 @@ module TivoHMO
|
|
16
16
|
super(delegate.key)
|
17
17
|
|
18
18
|
self.title = delegate.title
|
19
|
-
|
20
|
-
|
19
|
+
self.modified_at = Time.at(delegate.updated_at.to_i) rescue nil
|
20
|
+
self.created_at = Time.at(delegate.added_at.to_i) rescue nil
|
21
21
|
end
|
22
22
|
|
23
23
|
def children
|
@@ -34,11 +34,11 @@ module TivoHMO
|
|
34
34
|
add_child(QualifiedCategory.new(delegate, :by_first_character, :first_characters))
|
35
35
|
|
36
36
|
#add_child(Category.new(delegate, :unwatched))
|
37
|
-
add_child(Category.new(delegate, :on_deck))
|
38
|
-
add_child(Category.new(delegate, :newest))
|
39
|
-
add_child(Category.new(delegate, :recently_viewed))
|
40
|
-
add_child(Category.new(delegate, :recently_added))
|
41
|
-
add_child(Category.new(delegate, :all))
|
37
|
+
add_child(Category.new(delegate, :on_deck, nil, true))
|
38
|
+
add_child(Category.new(delegate, :newest, nil, true))
|
39
|
+
add_child(Category.new(delegate, :recently_viewed, nil, true))
|
40
|
+
add_child(Category.new(delegate, :recently_added, nil, true))
|
41
|
+
add_child(Category.new(delegate, :all, nil, true))
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -9,7 +9,11 @@ module TivoHMO
|
|
9
9
|
|
10
10
|
def initialize(item)
|
11
11
|
super(item)
|
12
|
-
|
12
|
+
end
|
13
|
+
|
14
|
+
def transcode(writeable_io, format="video/x-tivo-mpeg")
|
15
|
+
# TODO: mark as watched in plex
|
16
|
+
super
|
13
17
|
end
|
14
18
|
|
15
19
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module TivoHMO
|
2
|
+
module Adapters
|
3
|
+
module Settings
|
4
|
+
|
5
|
+
# An Application for live modification of settings
|
6
|
+
class Application
|
7
|
+
include TivoHMO::API::Application
|
8
|
+
include GemLogger::LoggerSupport
|
9
|
+
include MonitorMixin
|
10
|
+
|
11
|
+
def initialize(identifier)
|
12
|
+
super("Settings")
|
13
|
+
|
14
|
+
self.metadata_class = TivoHMO::Adapters::Settings::Metadata
|
15
|
+
self.transcoder_class = TivoHMO::Adapters::Settings::Transcoder
|
16
|
+
self.title = self.identifier
|
17
|
+
self.presorted = true
|
18
|
+
end
|
19
|
+
|
20
|
+
def children
|
21
|
+
synchronize do
|
22
|
+
if super.blank?
|
23
|
+
Config.instance.known_config.keys.sort.each do |k|
|
24
|
+
add_child(KeyContainer.new(k))
|
25
|
+
end
|
26
|
+
add_child(ResetDefaultsItem.new)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
super
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,35 @@
|
|
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 displaying a string
|
9
|
+
class DisplayItem
|
10
|
+
include TivoHMO::API::Item
|
11
|
+
include GemLogger::LoggerSupport
|
12
|
+
include MonitorMixin
|
13
|
+
|
14
|
+
def initialize(name, description=nil)
|
15
|
+
super(name)
|
16
|
+
@description = description
|
17
|
+
end
|
18
|
+
|
19
|
+
def metadata
|
20
|
+
md = super
|
21
|
+
|
22
|
+
if @description.nil?
|
23
|
+
md.description = "Nothing to do here, hit back to return"
|
24
|
+
else
|
25
|
+
md.description = @description + ". Nothing to do here, hit back to return"
|
26
|
+
end
|
27
|
+
|
28
|
+
md
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|