tivohmo 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +5 -0
  3. data/README.md +8 -0
  4. data/TODO +4 -0
  5. data/lib/tivohmo/adapters/filesystem/application.rb +37 -0
  6. data/lib/tivohmo/adapters/filesystem/file_item.rb +3 -1
  7. data/lib/tivohmo/adapters/filesystem/folder_container.rb +33 -29
  8. data/lib/tivohmo/adapters/filesystem/group.rb +22 -0
  9. data/lib/tivohmo/adapters/filesystem.rb +1 -0
  10. data/lib/tivohmo/adapters/plex/category.rb +20 -13
  11. data/lib/tivohmo/adapters/plex/episode.rb +2 -2
  12. data/lib/tivohmo/adapters/plex/movie.rb +2 -2
  13. data/lib/tivohmo/adapters/streamio/transcoder.rb +4 -13
  14. data/lib/tivohmo/api/container.rb +4 -1
  15. data/lib/tivohmo/subtitles_util.rb +109 -0
  16. data/lib/tivohmo/version.rb +1 -1
  17. data/spec/adapters/filesystem/application_spec.rb +66 -0
  18. data/spec/adapters/filesystem/file_item_spec.rb +12 -0
  19. data/spec/adapters/filesystem/folder_container_spec.rb +23 -21
  20. data/spec/adapters/plex/category_spec.rb +15 -5
  21. data/spec/adapters/plex/episode_spec.rb +11 -0
  22. data/spec/adapters/plex/movie_spec.rb +11 -0
  23. data/spec/adapters/streamio/transcoder_spec.rb +24 -0
  24. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_have_children.yml +698 -168
  25. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_have_children_with_embedded_subtitles.yml +22 -22
  26. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_have_children_with_subtitles.yml +262 -91
  27. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Episode/_initialize/should_instantiate_with_subtitle.yml +444 -0
  28. data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Movie/_initialize/should_instantiate_with_subtitle.yml +334 -0
  29. data/spec/spec_helper.rb +21 -0
  30. data/spec/subtitles_util_spec.rb +68 -0
  31. data/tivohmo.gemspec +1 -0
  32. metadata +24 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bf38e58ce80df9b5a177019960ace75cee1214cd
4
- data.tar.gz: 84358dcbc8cc552c560a34b67cd3bec1f40d7d62
3
+ metadata.gz: 23e9f9103ee58ffb81e0bb0bbd17e8d3362ead11
4
+ data.tar.gz: 62c368b9bb3d2e760d8fef53a4a309d34c0a14f9
5
5
  SHA512:
6
- metadata.gz: 1643360b023aa69207324541bfd041b25ce3d07e7211aa57bc7a3b33ab6b497c6063a560ba26ebe0f577e18a4fc8361838de7778b5758b5250b06f59996e62be
7
- data.tar.gz: 807c936f1152bb55a0a62ddcb6c933aaa0c03d19c44cf407fde517f283ca16c8e3ccb6fb2d84744090f3cb90885077fbde392fc831ac75540d59ab85af34fee0
6
+ metadata.gz: 7e61409326f627087d50ea35a95ec391d74ded1fde2b446f7e67398f063a0219e98e2c6f7daedf689fcb438d8728cee318965317b52e21fce51fddef3cfc2cca
7
+ data.tar.gz: 641ca50d1d8fc479fc85ebc16d0b4cd9977aa011d930196e92a758bcc7019498c1a88b3fcd03a5a600bbe869138ce758a86c40cb510ae9e3e8b71f8a9744d38f
data/CHANGELOG CHANGED
@@ -1,3 +1,8 @@
1
+ 0.3.1 (03/08/2015)
2
+ ------------------
3
+
4
+ refactored subtitles support, add subtitles to filesystem app, refactor change listeners in filesystem app <9820722> [Matt Conway]
5
+
1
6
  0.3.0 (03/01/2015)
2
7
  ------------------
3
8
 
data/README.md CHANGED
@@ -15,6 +15,14 @@ A Plex adapter is also available with similar functionality. The transcoding on
15
15
 
16
16
  This project only supports serving of video resources (for now) as that fills my need.
17
17
 
18
+ ## Noteworthy features
19
+
20
+ * Full control of runtime from command line or config file
21
+ * Application for changing runtime settings of the server from the Tivo UI
22
+ * Application to serve video to the Tivo from the Filesystem
23
+ * Application to serve video to the Tivo from a Plex Media Server
24
+ * Can serve video with on-the-fly hardcoded subtitles from srt files (embedded subs are also supported in plex app)
25
+
18
26
  ## Installation
19
27
 
20
28
  Install the gem:
data/TODO CHANGED
@@ -1 +1,5 @@
1
1
  fix back after watching movie (anchor)
2
+ add audio track support similar to embedded subtitles
3
+ add embedded subtitles to filesystem app
4
+ figure out how to stream/transcode from plex rather than hack to use local files
5
+ figure out a way to embed subtitles in mpeg2 stream for live toggling from tivo ui (EIA-608/CEA-708/line 21)
@@ -1,5 +1,6 @@
1
1
  require 'active_support/core_ext/string/inflections'
2
2
  require 'tivohmo/adapters/streamio'
3
+ require 'listen'
3
4
 
4
5
  module TivoHMO
5
6
  module Adapters
@@ -15,7 +16,43 @@ module TivoHMO
15
16
  super(identifier)
16
17
  self.metadata_class = TivoHMO::Adapters::StreamIO::Metadata
17
18
  self.transcoder_class = TivoHMO::Adapters::StreamIO::Transcoder
19
+
20
+ setup_change_listener
21
+ end
22
+
23
+ private
24
+
25
+ def setup_change_listener
26
+ logger.debug "Setting up change listener on #{identifier}"
27
+
28
+ fq_path = File.realdirpath(identifier)
29
+ listener = Listen.to(fq_path) do |modified, added, removed|
30
+ logger.debug "Detected filesystem change on #{identifier}"
31
+
32
+ dirs = (modified + added + removed).flatten.collect do |path|
33
+ relative_path = path.sub(fq_path, '')
34
+ relative_dir = File.dirname(relative_path).sub(/^\//, '')
35
+ end
36
+ dirs.uniq!
37
+
38
+ dirs.each do |dir|
39
+ begin
40
+ logger.debug "Handling filesystem change: #{dir.inspect}"
41
+ title_path = dir.split('/').collect(&:titleize).join('/')
42
+ # TODO fix Node#find
43
+ container = title_path.blank? ? self : find(title_path)
44
+ container.refresh if container
45
+ rescue Exception => e
46
+ logger.log_exception(e, "Ignoring exception in filesystem refresh: #{path}")
47
+ end
48
+ end
49
+
50
+ logger.debug "Completed filesystem refresh on #{identifier}"
51
+ end
52
+
53
+ listener.start
18
54
  end
55
+
19
56
  end
20
57
 
21
58
  end
@@ -9,14 +9,16 @@ module TivoHMO
9
9
  include TivoHMO::API::Item
10
10
  include GemLogger::LoggerSupport
11
11
 
12
- def initialize(identifier)
12
+ def initialize(identifier, subtitle=nil)
13
13
  full_path = File.expand_path(identifier)
14
14
  raise ArgumentError, "Must provide an existing file" unless File.file?(full_path)
15
15
 
16
16
  super(full_path)
17
17
 
18
18
  self.file = full_path
19
+ self.subtitle = subtitle
19
20
  self.title = File.basename(self.identifier)
21
+ self.title = "[#{subtitle.language_code} #{subtitle.type} sub] #{self.title}" if subtitle
20
22
  self.modified_at = File.mtime(self.identifier)
21
23
  self.created_at = File.ctime(self.identifier)
22
24
  end
@@ -1,5 +1,5 @@
1
1
  require 'active_support/core_ext/string/inflections'
2
- require 'listen'
2
+ require 'tivohmo/subtitles_util'
3
3
 
4
4
  module TivoHMO
5
5
  module Adapters
@@ -10,6 +10,7 @@ module TivoHMO
10
10
  include TivoHMO::API::Container
11
11
  include GemLogger::LoggerSupport
12
12
  include MonitorMixin
13
+ include TivoHMO::Config::Mixin
13
14
 
14
15
  VIDEO_EXTENSIONS = %w[
15
16
  tivo mpg avi wmv mov flv f4v vob mp4 m4v mkv
@@ -40,26 +41,29 @@ module TivoHMO
40
41
  self.modified_at = File.mtime(self.identifier)
41
42
  self.created_at = File.ctime(self.identifier)
42
43
 
43
- setup_change_listener
44
+ @subtitles = config_get(:enable_subtitles)
44
45
  end
45
46
 
46
47
  def children
47
48
  synchronize do
48
- if super.blank?
49
- folders = []
50
- files = []
49
+ if super.blank? || @subtitles != config_get(:enable_subtitles)
50
+ super.clear
51
+ @subtitles = config_get(:enable_subtitles)
51
52
 
52
- Dir["#{self.full_path}/*"].each do |path|
53
+ items = Dir["#{self.full_path}/*"].group_by do |path|
53
54
  if allowed_container?(path)
54
- folders << FolderContainer.new(path)
55
+ :dir
55
56
  elsif allowed_item?(path)
56
- files << FileItem.new(path)
57
+ :file
57
58
  else
58
- logger.debug "Ignoring: #{path}"
59
+ :skipped
59
60
  end
60
61
  end
61
62
 
62
- (folders + files).each {|c| add_child(c) }
63
+ Array(items[:dir]).each {|path| add_child(FolderContainer.new(path)) }
64
+ Array(items[:file]).each {|path| add_grouped(path) }
65
+ Array(items[:skipped]).each {|path| logger.debug "Ignoring: #{path}" } if logger.debug?
66
+
63
67
  end
64
68
  end
65
69
 
@@ -68,25 +72,6 @@ module TivoHMO
68
72
 
69
73
  protected
70
74
 
71
- def setup_change_listener
72
- logger.debug "Setting up change listener on #{identifier}"
73
- @listener = Listen.to(identifier, ignore: /\//) do |modified, added, removed|
74
- logger.debug "Detected filesystem change on #{identifier}"
75
- logger.debug "modified: #{modified}"
76
- logger.debug "added: #{added}"
77
- logger.debug "removed: #{removed}"
78
-
79
- # TODO: be more intelligent instead of just wiping children to cause the refresh
80
- self.refresh
81
-
82
- # cleanup - not strictly correct as this listener won't necessarily get triggered
83
- # if self is removed from the parent
84
- @listener.stop unless root.find(title_path)
85
- logger.debug "Completed filesystem refresh on #{identifier}"
86
- end
87
- @listener.start
88
- end
89
-
90
75
  def allowed_container?(path)
91
76
  File.directory?(path) && allowed_item_types.include?(:dir)
92
77
  end
@@ -98,6 +83,25 @@ module TivoHMO
98
83
  allowed_item_extensions.include?(ext)
99
84
  end
100
85
 
86
+ def add_grouped(path)
87
+ primary = FileItem.new(path)
88
+
89
+ if @subtitles
90
+ subs = SubtitlesUtil.instance.subtitles_for_media_file(path)
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(FileItem.new(path, s)) }
97
+ else
98
+ add_child(primary)
99
+ end
100
+ else
101
+ add_child(primary)
102
+ end
103
+ end
104
+
101
105
  end
102
106
 
103
107
  end
@@ -0,0 +1,22 @@
1
+ module TivoHMO
2
+ module Adapters
3
+ module Filesystem
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
+ self.modified_at = File.mtime(self.identifier)
15
+ self.created_at = File.ctime(self.identifier)
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -1,3 +1,4 @@
1
1
  require_relative 'filesystem/file_item'
2
+ require_relative 'filesystem/group'
2
3
  require_relative 'filesystem/folder_container'
3
4
  require_relative 'filesystem/application'
@@ -1,3 +1,6 @@
1
+ require 'tivohmo/subtitles_util'
2
+ require 'iso-639'
3
+
1
4
  module TivoHMO
2
5
  module Adapters
3
6
  module Plex
@@ -107,6 +110,10 @@ module TivoHMO
107
110
 
108
111
  source_filename = CGI.unescape(item_delegate.medias.first.parts.first.file)
109
112
 
113
+ # add in the file based subtitles
114
+ subs.concat(SubtitlesUtil.instance.subtitles_for_media_file(source_filename))
115
+
116
+ # add in the embedded subtitles
110
117
  item_delegate.medias.each do |media|
111
118
  media.parts.each do |part|
112
119
  prev_stream_count = 0
@@ -116,25 +123,25 @@ module TivoHMO
116
123
  # stream.key.present? means file based srt
117
124
  # stream.index and no key, means embedded
118
125
  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?
126
+ if stream.respond_to?(:index) && stream.index.present?
128
127
  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 || "???"
128
+
129
+ lang_code = stream.respond_to?(:language_code) && stream.language_code || "??"
130
+ st.language_code = lang_code
131
+
132
+ iso_entry = ISO_639.find_by_code(lang_code.downcase)
133
+ if iso_entry
134
+ st.language = iso_entry.english_name
135
+ else
136
+ logger.warn "Subtitle stream has unknown language code: #{lang_code}"
137
+ st.language = "Unknown"
138
+ end
139
+
131
140
  st.format = stream.codec
132
141
  st.type = :embedded
133
142
  # subtitle index should be the index amongst just the embedded subtitle streams
134
143
  st.location = stream.index.to_i - prev_stream_count
135
144
  subs << st
136
- else
137
- logger.warn "Unrecognized subtitle for #{item_delegate.title}"
138
145
  end
139
146
  end
140
147
 
@@ -9,7 +9,7 @@ module TivoHMO
9
9
  include GemLogger::LoggerSupport
10
10
  include TivoHMO::Config::Mixin
11
11
 
12
- attr_reader :delegate, :subtitle
12
+ attr_reader :delegate
13
13
 
14
14
  config_register(:group_with_zap2it, true,
15
15
  "Use zap2it ID for grouping episodes (Gives thumbnail in My Shows, but can cause problems)")
@@ -24,7 +24,7 @@ module TivoHMO
24
24
  self.subtitle = subtitle
25
25
 
26
26
  self.title = delegate.title
27
- self.title = "[#{subtitle.language_code} sub] #{self.title}" if subtitle
27
+ self.title = "[#{subtitle.language_code} #{subtitle.type} sub] #{self.title}" if subtitle
28
28
 
29
29
  self.modified_at = Time.at(delegate.updated_at.to_i)
30
30
  self.created_at = Time.parse(delegate.originally_available_at) rescue nil
@@ -6,7 +6,7 @@ module TivoHMO
6
6
  include TivoHMO::API::Item
7
7
  include GemLogger::LoggerSupport
8
8
 
9
- attr_reader :delegate, :subtitle
9
+ attr_reader :delegate
10
10
 
11
11
  def initialize(delegate, subtitle=nil)
12
12
  # delegate is a Plex::Movie
@@ -18,7 +18,7 @@ module TivoHMO
18
18
  self.subtitle = subtitle
19
19
 
20
20
  self.title = delegate.title
21
- self.title = "[#{subtitle.language_code} sub] #{self.title}" if subtitle
21
+ self.title = "[#{subtitle.language_code} #{subtitle.type} sub] #{self.title}" if subtitle
22
22
 
23
23
  self.modified_at = Time.at(delegate.updated_at.to_i)
24
24
  self.created_at = Time.parse(delegate.originally_available_at) rescue nil
@@ -209,20 +209,11 @@ module TivoHMO
209
209
  code = st.language_code
210
210
  file = st.location
211
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}\""
212
+ if File.exist?(file)
213
+ logger.info "Using subtitles present at: #{file}"
214
+ opts[:custom] << "-vf subtitles=\"#{file}\""
224
215
  else
225
- logger.error "Subtitle doesn't exist at: #{file_glob}"
216
+ logger.error "Subtitle doesn't exist at: #{file}"
226
217
  end
227
218
  when :embedded
228
219
  file = item.file
@@ -9,6 +9,7 @@ module TivoHMO
9
9
  extend ActiveSupport::Concern
10
10
  include Node
11
11
  include GemLogger::LoggerSupport
12
+ include MonitorMixin
12
13
 
13
14
  attr_accessor :uuid, :presorted
14
15
 
@@ -23,7 +24,9 @@ module TivoHMO
23
24
  end
24
25
 
25
26
  def refresh
26
- self.children = []
27
+ synchronize do
28
+ self.children.clear
29
+ end
27
30
  end
28
31
 
29
32
  def child_count
@@ -0,0 +1,109 @@
1
+ require 'iso-639'
2
+ require 'listen'
3
+
4
+ module TivoHMO
5
+
6
+ class SubtitlesUtil
7
+ include GemLogger::LoggerSupport
8
+ include MonitorMixin
9
+ include Singleton
10
+
11
+ ALLOWED_SUBTITLE_FORMATS = %w[srt]
12
+
13
+ def subtitles_for_media_file(media_path)
14
+ synchronize do
15
+ fq_path = File.realdirpath(media_path)
16
+ base_dir = File.dirname(fq_path)
17
+ base_file = fq_path.chomp(File.extname(fq_path))
18
+ Array(subtitles_for_dir(base_dir)[base_file])
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def refresh_subtitles(dir)
25
+ synchronize do
26
+ @subtitle_files ||= {}
27
+ @subtitle_files[dir] = nil
28
+ end
29
+ end
30
+
31
+ def subtitles_for_dir(dir)
32
+ @subtitle_files ||= {}
33
+ @subtitle_files[dir] ||= begin
34
+ subs = {}
35
+
36
+ Dir["#{dir}/*"].each do |f|
37
+ # /path/to/movie.<lang_code>.srt
38
+ pieces = f.scan(/(.+)\.(\w+)\.(\w+)$/).flatten
39
+ next if pieces.size != 3
40
+
41
+ format = pieces[-1].downcase
42
+ next unless ALLOWED_SUBTITLE_FORMATS.include?(format)
43
+
44
+ lang_code = pieces[-2]
45
+ base_path = pieces[-3]
46
+
47
+ sub = create_subtitle(f, lang_code, format)
48
+ next unless sub
49
+
50
+ subs[base_path] ||= []
51
+ subs[base_path] << sub
52
+ end
53
+
54
+ setup_change_listener(dir) unless @subtitle_files.has_key?(dir)
55
+
56
+ subs
57
+ end
58
+ end
59
+
60
+ def create_subtitle(subtitle_file, lang_code, format)
61
+ iso_entry = ISO_639.find_by_code(lang_code.downcase)
62
+ if iso_entry.nil?
63
+ logger.warn "Subtitle filename has invalid language code: #{subtitle_file}"
64
+ return nil
65
+ end
66
+
67
+ st = TivoHMO::API::Subtitle.new
68
+ st.language = iso_entry.english_name
69
+ # use the verbatim code as we could have multiple due to case insensitive fs
70
+ st.language_code = lang_code
71
+ st.format = format
72
+ st.type = :file
73
+ st.location = subtitle_file
74
+
75
+ st
76
+ end
77
+
78
+ def setup_change_listener(dir)
79
+ logger.debug "Setting up change listener on #{dir}"
80
+
81
+ listener = Listen.to(dir) do |modified, added, removed|
82
+ logger.debug "Detected filesystem change on #{dir}"
83
+
84
+ dirs = (added + removed).flatten.collect do |path|
85
+ logger.debug "Inspecting filesystem change: #{path}"
86
+
87
+ if ALLOWED_SUBTITLE_FORMATS.include?(File.extname(path)[1..-1])
88
+ File.dirname(path)
89
+ else
90
+ nil
91
+ end
92
+ end
93
+ dirs = dirs.compact.uniq
94
+
95
+ dirs.each do |dir|
96
+ logger.debug "Handling filesystem change: #{dir.inspect}"
97
+ refresh_subtitles(dir)
98
+ end
99
+
100
+ logger.debug "Completed filesystem refresh on #{dir}"
101
+ end
102
+
103
+ listener.start
104
+ listener
105
+ end
106
+
107
+ end
108
+
109
+ end
@@ -1,3 +1,3 @@
1
1
  module TivoHMO
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
@@ -16,4 +16,70 @@ describe TivoHMO::Adapters::Filesystem::Application do
16
16
 
17
17
  end
18
18
 
19
+ describe "#children" do
20
+
21
+ it "watches for filesystem addition in self" do
22
+ with_file_tree('1.avi', foo: ['2.avi']) do |dir|
23
+ subject = described_class.new(dir)
24
+ expect(subject.children.collect(&:title)).to match_array ['1.avi', 'Foo']
25
+ FileUtils.touch "#{dir}/3.avi"
26
+ sleep 0.5
27
+ expect(subject.children.collect(&:title)).to match_array ['3.avi','1.avi', 'Foo']
28
+ end
29
+ end
30
+
31
+ it "watches for filesystem addition in children" do
32
+ with_file_tree('1.avi', foo: ['2.avi']) do |dir|
33
+ subject = described_class.new(dir)
34
+ expect(subject.children.collect(&:title)).to match_array ['1.avi', 'Foo']
35
+ FileUtils.touch "#{dir}/foo/3.avi"
36
+ sleep 0.5
37
+ expect(subject.find("Foo").children.collect(&:title)).to match_array ['3.avi','2.avi']
38
+ end
39
+ end
40
+
41
+ it "watches for filesystem removal in self" do
42
+ with_file_tree('1.avi', foo: ['2.avi']) do |dir|
43
+ subject = described_class.new(dir)
44
+ expect(subject.children.collect(&:title)).to match_array ['1.avi', 'Foo']
45
+ FileUtils.rm "#{dir}/1.avi"
46
+ sleep 0.5
47
+ expect(subject.children.collect(&:title)).to match_array ['Foo']
48
+ end
49
+ end
50
+
51
+ it "watches for filesystem removal in children" do
52
+ with_file_tree('1.avi', foo: ['2.avi']) do |dir|
53
+ subject = described_class.new(dir)
54
+ expect(subject.children.collect(&:title)).to match_array ['1.avi', 'Foo']
55
+ FileUtils.rm "#{dir}/foo/2.avi"
56
+ sleep 0.5
57
+ expect(subject.find("Foo").children.collect(&:title)).to match_array []
58
+ end
59
+ end
60
+
61
+ it "watches for filesystem mod in self" do
62
+ with_file_tree('1.avi', foo: ['2.avi']) do |dir|
63
+ subject = described_class.new(dir)
64
+ orig = subject.find('1.avi')
65
+ sleep 1
66
+ FileUtils.touch "#{dir}/1.avi"
67
+ sleep 0.5
68
+ expect(subject.find('1.avi')).to_not eq(orig)
69
+ end
70
+ end
71
+
72
+ it "watches for filesystem mod in children" do
73
+ with_file_tree('1.avi', foo: ['2.avi']) do |dir|
74
+ subject = described_class.new(dir)
75
+ orig = subject.find('Foo/2.avi')
76
+ sleep 1
77
+ FileUtils.touch "#{dir}/foo/2.avi"
78
+ sleep 0.5
79
+ expect(subject.find('Foo/2.avi')).to_not eq(orig)
80
+ end
81
+ end
82
+
83
+ end
84
+
19
85
  end
@@ -26,6 +26,18 @@ describe TivoHMO::Adapters::Filesystem::FileItem do
26
26
  expect(subject.created_at).to_not be_nil
27
27
  end
28
28
 
29
+ it "should instantiate with subtitle" do
30
+ file = __FILE__
31
+ st = TivoHMO::API::Subtitle.new()
32
+ st.language_code = 'en'
33
+ st.language = 'English'
34
+ st.type = :file
35
+ subject = described_class.new(file, st)
36
+ expect(subject).to be_a described_class
37
+ expect(subject.subtitle).to eq(st)
38
+ expect(subject.title).to eq "[en file sub] #{File.basename(file)}"
39
+ end
40
+
29
41
  end
30
42
 
31
43
  end
@@ -80,33 +80,35 @@ describe TivoHMO::Adapters::Filesystem::FolderContainer do
80
80
  expect(subject.children.object_id).to eq subject.children.object_id
81
81
  end
82
82
 
83
- it "watches for filesystem addition" do
84
- with_file_tree('1.avi', foo: ['2.avi']) do |dir|
83
+ it "should have children with subtitles" do
84
+ with_file_tree('1.avi', '1.en.srt', '2.avi') do |dir|
85
+ described_class.config_set(:enable_subtitles, true)
85
86
  subject = described_class.new(dir)
86
- expect(subject.children.collect(&:title)).to match_array ['1.avi', 'Foo']
87
- FileUtils.touch "#{dir}/3.avi"
88
- sleep 0.5
89
- expect(subject.children.collect(&:title)).to match_array ['3.avi','1.avi', 'Foo']
90
- end
91
- end
92
87
 
93
- it "watches for filesystem removal" do
94
- with_file_tree('1.avi', foo: ['2.avi']) do |dir|
95
- subject = described_class.new(dir)
96
- expect(subject.children.collect(&:title)).to match_array ['1.avi', 'Foo']
97
- FileUtils.rm "#{dir}/1.avi"
98
- sleep 0.5
99
- expect(subject.children.collect(&:title)).to match_array ['Foo']
88
+ expect(subject.children.collect(&:title)).to match_array ['1.avi', '2.avi']
89
+
90
+ subgroup = subject.children.find {|c| c.is_a?(TivoHMO::Adapters::Filesystem::Group) }
91
+ expect(subgroup).to_not be_nil
92
+ primary = subgroup.children[0]
93
+ sub = subgroup.children[1]
94
+ expect(primary.title).to_not match(/sub\]/)
95
+ expect(sub.title).to match(primary.title)
96
+ expect(sub.title).to match(/sub\]/)
97
+ expect(sub.subtitle.language).to_not be_nil
98
+ expect(sub.subtitle.language_code).to_not be_nil
99
+ expect(sub.subtitle.location).to_not be_nil
100
+
101
+ withoutsub = subject.children.find {|c| ! c.is_a?(TivoHMO::Adapters::Filesystem::Group) }
102
+ expect(withoutsub).to_not be_nil
100
103
  end
101
104
  end
102
105
 
103
- it "doesn't watch children" do
104
- with_file_tree('1.avi', foo: ['2.avi']) do |dir|
106
+ it "should allow disabling subtitles" do
107
+ with_file_tree('1.avi', '1.en.srt', '2.avi') do |dir|
108
+ described_class.config_set(:enable_subtitles, false)
105
109
  subject = described_class.new(dir)
106
- oldid = subject.children.object_id
107
- FileUtils.touch "#{dir}/foo/3.avi"
108
- sleep 0.5
109
- expect(subject.children.object_id).to eq oldid
110
+ withsub = subject.children.find {|c| c.is_a?(TivoHMO::Adapters::Filesystem::Group) }
111
+ expect(withsub).to be_nil
110
112
  end
111
113
  end
112
114