mm_tool 0.1.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 +7 -0
- data/.gitattributes +4 -0
- data/.gitignore +24 -0
- data/Gemfile +3 -0
- data/LICENSE.md +22 -0
- data/README.md +15 -0
- data/Rakefile +2 -0
- data/Truth Tables.xlsx +0 -0
- data/bin/console +14 -0
- data/bin/mm_tool +19 -0
- data/bin/setup +8 -0
- data/lib/mm_tool.rb +21 -0
- data/lib/mm_tool/application_main.rb +172 -0
- data/lib/mm_tool/mm_movie.rb +217 -0
- data/lib/mm_tool/mm_movie_ignore_list.rb +68 -0
- data/lib/mm_tool/mm_movie_stream.rb +492 -0
- data/lib/mm_tool/mm_tool_cli.rb +322 -0
- data/lib/mm_tool/mm_user_defaults.rb +290 -0
- data/lib/mm_tool/output_helper.rb +121 -0
- data/lib/mm_tool/user_defaults.rb +377 -0
- data/lib/mm_tool/version.rb +3 -0
- data/mm_tool.gemspec +50 -0
- metadata +155 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
module MmTool
|
2
|
+
|
3
|
+
#=============================================================================
|
4
|
+
# A list of movie files to ignore during :normal and :all scan types. Will
|
5
|
+
# keep the on-file list in sync with the in-memory list.
|
6
|
+
#=============================================================================
|
7
|
+
class MmMovieIgnoreList
|
8
|
+
|
9
|
+
require 'fileutils'
|
10
|
+
require 'yaml'
|
11
|
+
|
12
|
+
#------------------------------------------------------------
|
13
|
+
# Singleton accessor.
|
14
|
+
#------------------------------------------------------------
|
15
|
+
def self.shared_ignore_list
|
16
|
+
unless @self
|
17
|
+
@self = self.new
|
18
|
+
end
|
19
|
+
@self
|
20
|
+
end
|
21
|
+
|
22
|
+
#------------------------------------------------------------
|
23
|
+
# Initialize
|
24
|
+
#------------------------------------------------------------
|
25
|
+
def initialize
|
26
|
+
@ignore_list = []
|
27
|
+
if !File.file?(file_path)
|
28
|
+
FileUtils.mkdir_p(File.dirname(file_path))
|
29
|
+
else
|
30
|
+
#noinspection RubyResolve
|
31
|
+
@ignore_list = YAML.load(File.read(file_path))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
#------------------------------------------------------------
|
36
|
+
# The location on the filesystem where the file exists.
|
37
|
+
#------------------------------------------------------------
|
38
|
+
def file_path
|
39
|
+
PATH_IGNORE_LIST
|
40
|
+
end
|
41
|
+
|
42
|
+
#------------------------------------------------------------
|
43
|
+
# Is the given file on the ignore list?
|
44
|
+
#------------------------------------------------------------
|
45
|
+
def include?(path)
|
46
|
+
@ignore_list.include?(path)
|
47
|
+
end
|
48
|
+
|
49
|
+
#------------------------------------------------------------
|
50
|
+
# Add a path to the list, and write list to disk.
|
51
|
+
#------------------------------------------------------------
|
52
|
+
def add(path:)
|
53
|
+
new_list = @ignore_list |= [path]
|
54
|
+
@ignore_list = new_list.sort
|
55
|
+
File.open(file_path, 'w') { |file| file.write(@ignore_list.to_yaml) }
|
56
|
+
end
|
57
|
+
|
58
|
+
#------------------------------------------------------------
|
59
|
+
# Remove a path from the list, and update on disk.
|
60
|
+
#------------------------------------------------------------
|
61
|
+
def remove(path:)
|
62
|
+
@ignore_list.delete(path)
|
63
|
+
File.open(file_path, 'w') { |file| file.write(@ignore_list.to_yaml) }
|
64
|
+
end
|
65
|
+
|
66
|
+
end # class
|
67
|
+
|
68
|
+
end # module
|
@@ -0,0 +1,492 @@
|
|
1
|
+
module MmTool
|
2
|
+
|
3
|
+
#=============================================================================
|
4
|
+
# A stream of an MmMovie. Instances contain simple accessors to the data
|
5
|
+
# made available by ffmpeg, and have knowledge on how to generate useful
|
6
|
+
# arguments for ffmpeg and mkvpropedit.
|
7
|
+
#=============================================================================
|
8
|
+
class MmMovieStream
|
9
|
+
|
10
|
+
require 'streamio-ffmpeg'
|
11
|
+
require 'mm_tool/mm_movie'
|
12
|
+
|
13
|
+
#------------------------------------------------------------
|
14
|
+
# Given an array of related files, this class method returns
|
15
|
+
# an array of MmMovieStreams reflecting the streams present
|
16
|
+
# in each of them.
|
17
|
+
#------------------------------------------------------------
|
18
|
+
def self.streams(with_files:)
|
19
|
+
# Arrays are passed around by reference; when this array is created and
|
20
|
+
# used as a reference in each stream, and *also* returned from this class
|
21
|
+
# method, everyone will still be using the same reference. It's important
|
22
|
+
# below to build up this array without replacing it with another instance.
|
23
|
+
streams = []
|
24
|
+
with_files.each_with_index do |path, i|
|
25
|
+
ff_movie = FFMPEG::Movie.new(path)
|
26
|
+
ff_movie.metadata[:streams].each do |stream|
|
27
|
+
streams << MmMovieStream.new(stream_data: stream, source_file: path, file_number: i, streams_ref: streams)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
streams
|
31
|
+
end
|
32
|
+
|
33
|
+
#------------------------------------------------------------
|
34
|
+
# Initialize
|
35
|
+
#------------------------------------------------------------
|
36
|
+
def initialize(stream_data:, source_file:, file_number:, streams_ref:)
|
37
|
+
@defaults = MmUserDefaults.shared_user_defaults
|
38
|
+
@data = stream_data
|
39
|
+
@source_file = source_file
|
40
|
+
@file_number = file_number
|
41
|
+
@streams = streams_ref
|
42
|
+
end
|
43
|
+
|
44
|
+
#------------------------------------------------------------
|
45
|
+
# Attribute accessors
|
46
|
+
#------------------------------------------------------------
|
47
|
+
attr_accessor :file_number
|
48
|
+
attr_accessor :source_file
|
49
|
+
|
50
|
+
#------------------------------------------------------------
|
51
|
+
# Property - returns the index of the stream.
|
52
|
+
#------------------------------------------------------------
|
53
|
+
def index
|
54
|
+
@data[:index]
|
55
|
+
end
|
56
|
+
|
57
|
+
#------------------------------------------------------------
|
58
|
+
# Property - returns the input specifier of the stream.
|
59
|
+
#------------------------------------------------------------
|
60
|
+
def input_specifier
|
61
|
+
"#{@file_number}:#{index}"
|
62
|
+
end
|
63
|
+
|
64
|
+
#------------------------------------------------------------
|
65
|
+
# Property - returns the codec name of the stream.
|
66
|
+
#------------------------------------------------------------
|
67
|
+
def codec_name
|
68
|
+
@data[:codec_name]
|
69
|
+
end
|
70
|
+
|
71
|
+
#------------------------------------------------------------
|
72
|
+
# Property - returns the codec type of the stream.
|
73
|
+
#------------------------------------------------------------
|
74
|
+
def codec_type
|
75
|
+
@data[:codec_type]
|
76
|
+
end
|
77
|
+
|
78
|
+
#------------------------------------------------------------
|
79
|
+
# Property - returns the coded width of the stream.
|
80
|
+
#------------------------------------------------------------
|
81
|
+
def coded_width
|
82
|
+
@data[:coded_width]
|
83
|
+
end
|
84
|
+
|
85
|
+
#------------------------------------------------------------
|
86
|
+
# Property - returns the coded height of the stream.
|
87
|
+
#------------------------------------------------------------
|
88
|
+
def coded_height
|
89
|
+
@data[:coded_height]
|
90
|
+
end
|
91
|
+
|
92
|
+
#------------------------------------------------------------
|
93
|
+
# Property - returns the number of channels of the stream.
|
94
|
+
#------------------------------------------------------------
|
95
|
+
def channels
|
96
|
+
@data[:channels]
|
97
|
+
end
|
98
|
+
|
99
|
+
#------------------------------------------------------------
|
100
|
+
# Property - returns the channel layout of the stream.
|
101
|
+
#------------------------------------------------------------
|
102
|
+
def channel_layout
|
103
|
+
@data[:channel_layout]
|
104
|
+
end
|
105
|
+
|
106
|
+
#------------------------------------------------------------
|
107
|
+
# Property - returns the language of the stream, or 'und'
|
108
|
+
# if the language is not defined.
|
109
|
+
#------------------------------------------------------------
|
110
|
+
def language
|
111
|
+
if @data.key?(:tags)
|
112
|
+
lang = @data[:tags][:language]
|
113
|
+
lang = @data[:tags][:LANGUAGE] unless lang
|
114
|
+
lang = 'und' unless lang
|
115
|
+
else
|
116
|
+
lang = 'und'
|
117
|
+
end
|
118
|
+
lang
|
119
|
+
end
|
120
|
+
|
121
|
+
#------------------------------------------------------------
|
122
|
+
# Property - returns the title of the stream, or nil.
|
123
|
+
#------------------------------------------------------------
|
124
|
+
def title
|
125
|
+
if @data.key?(:tags)
|
126
|
+
@data[:tags][:title]
|
127
|
+
else
|
128
|
+
nil
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
#------------------------------------------------------------
|
133
|
+
# Property - returns the disposition flags of the stream as
|
134
|
+
# a comma-separated list for compactness.
|
135
|
+
#------------------------------------------------------------
|
136
|
+
def dispositions
|
137
|
+
MmMovie.dispositions
|
138
|
+
.collect {|symbol| @data[:disposition][symbol]}
|
139
|
+
.join(',')
|
140
|
+
end
|
141
|
+
|
142
|
+
#------------------------------------------------------------
|
143
|
+
# Property - returns an appropriate "quality" indicator
|
144
|
+
# based on the type of the stream.
|
145
|
+
#------------------------------------------------------------
|
146
|
+
def quality_01
|
147
|
+
if codec_type == 'audio'
|
148
|
+
channels
|
149
|
+
elsif codec_type == 'video'
|
150
|
+
coded_width
|
151
|
+
else
|
152
|
+
nil
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
#------------------------------------------------------------
|
157
|
+
# Property - returns a different appropriate "quality"
|
158
|
+
# indicator based on the type of the stream.
|
159
|
+
#------------------------------------------------------------
|
160
|
+
def quality_02
|
161
|
+
if codec_type == 'audio'
|
162
|
+
channel_layout
|
163
|
+
elsif codec_type == 'video'
|
164
|
+
coded_height
|
165
|
+
else
|
166
|
+
nil
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
#------------------------------------------------------------
|
171
|
+
# Property - returns a convenient label indicating the
|
172
|
+
# recommended actions for the stream.
|
173
|
+
#------------------------------------------------------------
|
174
|
+
def action_label
|
175
|
+
"#{output_specifier} #{actions.select {|a| a != :interesting}.join(' ')}"
|
176
|
+
end
|
177
|
+
|
178
|
+
#------------------------------------------------------------
|
179
|
+
# Property - indicates whether or not the stream is the
|
180
|
+
# default stream per its dispositions.
|
181
|
+
#------------------------------------------------------------
|
182
|
+
def default?
|
183
|
+
@data[:disposition][:default] == 1
|
184
|
+
end
|
185
|
+
|
186
|
+
#------------------------------------------------------------
|
187
|
+
# Property - indicates whether or not the stream is
|
188
|
+
# considered "low quality" based on the application
|
189
|
+
# configuration.
|
190
|
+
#------------------------------------------------------------
|
191
|
+
def low_quality?
|
192
|
+
if codec_type == 'audio'
|
193
|
+
channels.to_i < @defaults[:min_channels].to_i
|
194
|
+
elsif codec_type == 'video'
|
195
|
+
coded_width.to_i < @defaults[:min_width].to_i
|
196
|
+
else
|
197
|
+
false
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
#------------------------------------------------------------
|
202
|
+
# Property - stream action includes :drop?
|
203
|
+
#------------------------------------------------------------
|
204
|
+
def drop?
|
205
|
+
actions.include?(:drop)
|
206
|
+
end
|
207
|
+
|
208
|
+
#------------------------------------------------------------
|
209
|
+
# Property - stream action includes :copy?
|
210
|
+
#------------------------------------------------------------
|
211
|
+
def copy?
|
212
|
+
actions.include?(:copy)
|
213
|
+
end
|
214
|
+
|
215
|
+
#------------------------------------------------------------
|
216
|
+
# Property - stream action includes :transcode?
|
217
|
+
#------------------------------------------------------------
|
218
|
+
def transcode?
|
219
|
+
actions.include?(:transcode)
|
220
|
+
end
|
221
|
+
|
222
|
+
#------------------------------------------------------------
|
223
|
+
# Property - stream action includes :set_language?
|
224
|
+
#------------------------------------------------------------
|
225
|
+
def set_language?
|
226
|
+
actions.include?(:set_language)
|
227
|
+
end
|
228
|
+
|
229
|
+
#------------------------------------------------------------
|
230
|
+
# Property - stream action includes :interesting?
|
231
|
+
#------------------------------------------------------------
|
232
|
+
def interesting?
|
233
|
+
actions.include?(:interesting)
|
234
|
+
end
|
235
|
+
|
236
|
+
#------------------------------------------------------------
|
237
|
+
# Property - indicates whether or not the stream will be
|
238
|
+
# unique for its type at output.
|
239
|
+
#------------------------------------------------------------
|
240
|
+
def output_unique?
|
241
|
+
@streams.count {|s| s.codec_type == codec_type && !s.drop? } == 1
|
242
|
+
end
|
243
|
+
|
244
|
+
#------------------------------------------------------------
|
245
|
+
# Property - indicates whether or not this stream is the
|
246
|
+
# only one of its type.
|
247
|
+
#------------------------------------------------------------
|
248
|
+
def one_of_a_kind?
|
249
|
+
@streams.count {|s| s.codec_type == codec_type && s != self } == 0
|
250
|
+
end
|
251
|
+
|
252
|
+
#------------------------------------------------------------
|
253
|
+
# Property - returns the index of the stream in the output
|
254
|
+
# file.
|
255
|
+
#------------------------------------------------------------
|
256
|
+
def output_index
|
257
|
+
@streams.select {|s| !s.drop? }.index(self)
|
258
|
+
end
|
259
|
+
|
260
|
+
#------------------------------------------------------------
|
261
|
+
# Property - returns a specific output specifier for the
|
262
|
+
# stream, such as v:0 or a:2.
|
263
|
+
#------------------------------------------------------------
|
264
|
+
def output_specifier
|
265
|
+
idx = @streams.select {|s| s.codec_type == codec_type && !s.drop?}.index(self)
|
266
|
+
idx ? "#{codec_type[0]}:#{idx}" : ' ⬇ '
|
267
|
+
end
|
268
|
+
|
269
|
+
#------------------------------------------------------------
|
270
|
+
# Property - returns the -i input instruction for this
|
271
|
+
# stream.
|
272
|
+
#------------------------------------------------------------
|
273
|
+
def instruction_input
|
274
|
+
src = if @file_number == 0
|
275
|
+
File.join(File.dirname(@source_file), File.basename(@source_file, '.*') + @defaults[:suffix] + File.extname(@source_file))
|
276
|
+
else
|
277
|
+
@source_file
|
278
|
+
end
|
279
|
+
"-i \"#{src}\" \\"
|
280
|
+
end
|
281
|
+
|
282
|
+
#------------------------------------------------------------
|
283
|
+
# Property - returns the -map instruction for this stream,
|
284
|
+
# according to the action(s) determined.
|
285
|
+
#------------------------------------------------------------
|
286
|
+
def instruction_map
|
287
|
+
drop? ? nil : "-map #{input_specifier} \\"
|
288
|
+
end
|
289
|
+
|
290
|
+
#------------------------------------------------------------
|
291
|
+
# Property - returns an instruction for handling the stream,
|
292
|
+
# according to the action(s) determined.
|
293
|
+
#------------------------------------------------------------
|
294
|
+
def instruction_action
|
295
|
+
if copy?
|
296
|
+
"-codec:#{output_specifier} copy \\"
|
297
|
+
elsif transcode?
|
298
|
+
if codec_type == 'audio'
|
299
|
+
encode_to = @defaults[:codecs_audio_preferred][0]
|
300
|
+
elsif codec_type == 'video'
|
301
|
+
encode_to = @defaults[:codecs_video_preferred][0]
|
302
|
+
else
|
303
|
+
raise Exception.new "Error: somehow the program branched where it shouldn't have."
|
304
|
+
end
|
305
|
+
"-codec:#{output_specifier} #{encoder_string(for_codec: encode_to)} \\"
|
306
|
+
else
|
307
|
+
nil
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
#------------------------------------------------------------
|
312
|
+
# Property - returns an instruction for setting the metadata
|
313
|
+
# of the stream, if necessary.
|
314
|
+
#------------------------------------------------------------
|
315
|
+
def instruction_metadata
|
316
|
+
# We only want to set fixed_lang if options allow us to fix the language,
|
317
|
+
# and we want to set subtitle language from the filename, if applicable.
|
318
|
+
fixed_lang = @defaults[:fix_undefined_language] ? @defaults[:undefined_language] : nil
|
319
|
+
lang = subtitle_file_language ? subtitle_file_language : fixed_lang
|
320
|
+
set_language = set_language? ? "language=#{lang} " : nil
|
321
|
+
set_title = title && ! @defaults[:ignore_titles] ? "title=\"#{title}\" " : nil
|
322
|
+
|
323
|
+
if set_language || set_title
|
324
|
+
"-metadata:s:#{output_specifier} #{set_language}#{set_title}\\"
|
325
|
+
else
|
326
|
+
nil
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
#------------------------------------------------------------
|
331
|
+
# Property - returns an instruction for setting the stream's
|
332
|
+
# default disposition, if necessary.
|
333
|
+
#------------------------------------------------------------
|
334
|
+
def instruction_disposition
|
335
|
+
set_disposition = output_unique? && !default? && !drop? ? "default " : nil
|
336
|
+
|
337
|
+
if set_disposition
|
338
|
+
"-disposition:#{output_specifier} #{set_disposition}\\"
|
339
|
+
else
|
340
|
+
nil
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
|
345
|
+
#============================================================
|
346
|
+
private
|
347
|
+
#============================================================
|
348
|
+
|
349
|
+
|
350
|
+
#------------------------------------------------------------
|
351
|
+
# Property - returns an array of actions that are suggested
|
352
|
+
# for the stream based on quality, language, codec, etc.
|
353
|
+
#------------------------------------------------------------
|
354
|
+
def actions
|
355
|
+
|
356
|
+
#------------------------------------------------------------
|
357
|
+
# Note: logic below a result of Karnaugh mapping of the
|
358
|
+
# selection truth table for each desired action. There's
|
359
|
+
# probably an excel file somewhere in the repository.
|
360
|
+
#------------------------------------------------------------
|
361
|
+
|
362
|
+
if @actions.nil?
|
363
|
+
@actions = []
|
364
|
+
|
365
|
+
#––––––––––––––––––––––––––––––––––––––––––––––––––
|
366
|
+
# subtitle stream handler
|
367
|
+
#––––––––––––––––––––––––––––––––––––––––––––––––––
|
368
|
+
if codec_type == 'subtitle'
|
369
|
+
|
370
|
+
a = @defaults[:keep_langs_subs]&.include?(language)
|
371
|
+
b = @defaults[:codecs_subs_preferred]&.include?(codec_name)
|
372
|
+
c = language.downcase == 'und'
|
373
|
+
d = title != nil && ! @defaults[:ignore_titles]
|
374
|
+
|
375
|
+
if (!a && !c) || (!b)
|
376
|
+
@actions |= [:drop]
|
377
|
+
else
|
378
|
+
@actions |= [:copy]
|
379
|
+
end
|
380
|
+
|
381
|
+
if (b && c) && (@defaults[:fix_undefined_language])
|
382
|
+
@actions |= [:set_language]
|
383
|
+
end
|
384
|
+
|
385
|
+
if (!a || !b || c || (d))
|
386
|
+
@actions |= [:interesting]
|
387
|
+
end
|
388
|
+
|
389
|
+
#––––––––––––––––––––––––––––––––––––––––––––––––––
|
390
|
+
# video stream handler
|
391
|
+
#––––––––––––––––––––––––––––––––––––––––––––––––––
|
392
|
+
elsif codec_type == 'video'
|
393
|
+
|
394
|
+
a = codec_name.downcase == 'mjpeg'
|
395
|
+
b = @defaults[:codecs_video_preferred]&.include?(codec_name)
|
396
|
+
c = @defaults[:keep_langs_video]&.include?(language)
|
397
|
+
d = language.downcase == 'und'
|
398
|
+
e = title != nil && ! @defaults[:ignore_titles]
|
399
|
+
f = @defaults[:scan_type] == 'quality' && low_quality?
|
400
|
+
|
401
|
+
if (a)
|
402
|
+
@actions |= [:drop]
|
403
|
+
end
|
404
|
+
|
405
|
+
if (!a && b)
|
406
|
+
@actions |= [:copy]
|
407
|
+
end
|
408
|
+
|
409
|
+
if (!a && !b)
|
410
|
+
@actions |= [:transcode]
|
411
|
+
end
|
412
|
+
|
413
|
+
if (!a && d) && (@defaults[:fix_undefined_language])
|
414
|
+
@actions |= [:set_language]
|
415
|
+
end
|
416
|
+
|
417
|
+
if (a || !b || !c || d || e || f)
|
418
|
+
@actions |= [:interesting]
|
419
|
+
end
|
420
|
+
|
421
|
+
#––––––––––––––––––––––––––––––––––––––––––––––––––
|
422
|
+
# audio stream handler
|
423
|
+
#––––––––––––––––––––––––––––––––––––––––––––––––––
|
424
|
+
elsif codec_type == 'audio'
|
425
|
+
|
426
|
+
a = @defaults[:codecs_audio_preferred]&.include?(codec_name)
|
427
|
+
b = @defaults[:keep_langs_audio]&.include?(language)
|
428
|
+
c = language.downcase == 'und'
|
429
|
+
d = title != nil && ! @defaults[:ignore_titles]
|
430
|
+
e = @defaults[:scan_type] == 'quality' && low_quality?
|
431
|
+
|
432
|
+
if (!b && !c)
|
433
|
+
@actions |= one_of_a_kind? ? [:set_language] : [:drop]
|
434
|
+
end
|
435
|
+
|
436
|
+
if (a && b) || (a && !b && c)
|
437
|
+
@actions |= [:copy]
|
438
|
+
end
|
439
|
+
|
440
|
+
if (!a && !b && c) || (!a && b)
|
441
|
+
@actions |= [:transcode]
|
442
|
+
end
|
443
|
+
|
444
|
+
if (c) && (@defaults[:fix_undefined_language])
|
445
|
+
@actions |= [:set_language]
|
446
|
+
end
|
447
|
+
|
448
|
+
if (!a || !b || c || d || e)
|
449
|
+
@actions |= [:interesting]
|
450
|
+
end
|
451
|
+
|
452
|
+
#––––––––––––––––––––––––––––––––––––––––––––––––––
|
453
|
+
# other stream handler
|
454
|
+
#––––––––––––––––––––––––––––––––––––––––––––––––––
|
455
|
+
else
|
456
|
+
@actions |= [:drop]
|
457
|
+
end
|
458
|
+
end # if @actions.nil?
|
459
|
+
|
460
|
+
@actions
|
461
|
+
end # actions
|
462
|
+
|
463
|
+
#------------------------------------------------------------
|
464
|
+
# Given a codec, return the ffmpeg encoder string.
|
465
|
+
#------------------------------------------------------------
|
466
|
+
def encoder_string(for_codec:)
|
467
|
+
case for_codec.downcase
|
468
|
+
when 'hevc'
|
469
|
+
"libx265 -crf 28 -preset slow"
|
470
|
+
when 'h264'
|
471
|
+
"libx264 -crf 23 -preset slow"
|
472
|
+
when 'aac'
|
473
|
+
"libfdk_aac"
|
474
|
+
else
|
475
|
+
raise Exception.new "Error: somehow an unsupported codec '#{for_codec}' was specified."
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
#------------------------------------------------------------
|
480
|
+
# If the source file is an srt, and there's a language, and
|
481
|
+
# it's in the approved language list, then return it;
|
482
|
+
# otherwise return nil.
|
483
|
+
#------------------------------------------------------------
|
484
|
+
def subtitle_file_language
|
485
|
+
langs = @defaults[:keep_langs_subs]&.join('|')
|
486
|
+
lang = @source_file.match(/^.*\.(#{langs})\.srt$/)
|
487
|
+
lang ? lang[1] : nil
|
488
|
+
end
|
489
|
+
|
490
|
+
end # class
|
491
|
+
|
492
|
+
end # module
|