tivohmo 0.3.0 → 0.3.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG +5 -0
- data/README.md +8 -0
- data/TODO +4 -0
- data/lib/tivohmo/adapters/filesystem/application.rb +37 -0
- data/lib/tivohmo/adapters/filesystem/file_item.rb +3 -1
- data/lib/tivohmo/adapters/filesystem/folder_container.rb +33 -29
- data/lib/tivohmo/adapters/filesystem/group.rb +22 -0
- data/lib/tivohmo/adapters/filesystem.rb +1 -0
- data/lib/tivohmo/adapters/plex/category.rb +20 -13
- data/lib/tivohmo/adapters/plex/episode.rb +2 -2
- data/lib/tivohmo/adapters/plex/movie.rb +2 -2
- data/lib/tivohmo/adapters/streamio/transcoder.rb +4 -13
- data/lib/tivohmo/api/container.rb +4 -1
- data/lib/tivohmo/subtitles_util.rb +109 -0
- data/lib/tivohmo/version.rb +1 -1
- data/spec/adapters/filesystem/application_spec.rb +66 -0
- data/spec/adapters/filesystem/file_item_spec.rb +12 -0
- data/spec/adapters/filesystem/folder_container_spec.rb +23 -21
- data/spec/adapters/plex/category_spec.rb +15 -5
- data/spec/adapters/plex/episode_spec.rb +11 -0
- data/spec/adapters/plex/movie_spec.rb +11 -0
- data/spec/adapters/streamio/transcoder_spec.rb +24 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_have_children.yml +698 -168
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_have_children_with_embedded_subtitles.yml +22 -22
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Category/_children/should_have_children_with_subtitles.yml +262 -91
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Episode/_initialize/should_instantiate_with_subtitle.yml +444 -0
- data/spec/fixtures/vcr/TivoHMO_Adapters_Plex_Movie/_initialize/should_instantiate_with_subtitle.yml +334 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/subtitles_util_spec.rb +68 -0
- data/tivohmo.gemspec +1 -0
- metadata +24 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 23e9f9103ee58ffb81e0bb0bbd17e8d3362ead11
|
4
|
+
data.tar.gz: 62c368b9bb3d2e760d8fef53a4a309d34c0a14f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7e61409326f627087d50ea35a95ec391d74ded1fde2b446f7e67398f063a0219e98e2c6f7daedf689fcb438d8728cee318965317b52e21fce51fddef3cfc2cca
|
7
|
+
data.tar.gz: 641ca50d1d8fc479fc85ebc16d0b4cd9977aa011d930196e92a758bcc7019498c1a88b3fcd03a5a600bbe869138ce758a86c40cb510ae9e3e8b71f8a9744d38f
|
data/CHANGELOG
CHANGED
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 '
|
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
|
-
|
44
|
+
@subtitles = config_get(:enable_subtitles)
|
44
45
|
end
|
45
46
|
|
46
47
|
def children
|
47
48
|
synchronize do
|
48
|
-
if super.blank?
|
49
|
-
|
50
|
-
|
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}/*"].
|
53
|
+
items = Dir["#{self.full_path}/*"].group_by do |path|
|
53
54
|
if allowed_container?(path)
|
54
|
-
|
55
|
+
:dir
|
55
56
|
elsif allowed_item?(path)
|
56
|
-
|
57
|
+
:file
|
57
58
|
else
|
58
|
-
|
59
|
+
:skipped
|
59
60
|
end
|
60
61
|
end
|
61
62
|
|
62
|
-
(
|
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,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
|
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
|
-
|
130
|
-
|
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
|
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
|
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
|
-
|
213
|
-
|
214
|
-
|
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: #{
|
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
|
-
|
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
|
data/lib/tivohmo/version.rb
CHANGED
@@ -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 "
|
84
|
-
with_file_tree('1.avi',
|
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
|
-
|
94
|
-
|
95
|
-
|
96
|
-
expect(
|
97
|
-
|
98
|
-
|
99
|
-
expect(
|
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 "
|
104
|
-
with_file_tree('1.avi',
|
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
|
-
|
107
|
-
|
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
|
|