tivohmo 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|