Last active
August 29, 2015 14:20
-
-
Save msg7086/7cb9f08f5c9ffeced507 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'rake' | |
require 'time' | |
Encoding.default_internal = Encoding::UTF_8 | |
Encoding.default_external = Encoding::UTF_8 | |
class Timestamp | |
attr_reader :from, :to | |
def initialize from, to | |
@from = from.to_i | |
@to = to.to_i | |
end | |
def to_inc | |
@to + 1 | |
end | |
def duration | |
to_inc - from | |
end | |
end | |
class Fixnum | |
def to_time fps:, delay: 0 | |
(self / fps - delay / 1000.0).round(3) | |
end | |
end | |
class SubtitleLine | |
attr_reader :dialog | |
def initialize line | |
@text = line | |
@dialog = line['Dialogue'] ? true : false | |
if @dialog | |
@timepart = line[/([0-9:.]{10,10}),([0-9:.]{10,10})/] | |
@start = Time.parse("1/1/1970 #{$1} UTC").to_f | |
@end = Time.parse("1/1/1970 #{$2} UTC").to_f | |
end | |
end | |
def offset ms | |
@start += ms | |
@end += ms | |
@start = 0 if @start < 0 | |
@end = 0 if @end < 0 | |
start_text = Time.at(@start).utc.strftime('%-H:%M:%S.%2N') | |
end_text = Time.at(@end).utc.strftime('%-H:%M:%S.%2N') | |
@text[@timepart] = "#{start_text},#{end_text}" | |
end | |
def disable! | |
return if !@dialog | |
@dialog = false | |
@text = '; ' + @text | |
end | |
def between? from:, to: | |
@start > from && @start < to | |
end | |
def to_s | |
@text | |
end | |
end | |
class TSProcessor | |
include FileUtils | |
def initialize time: 'time.txt', fps: 24000.0/1001 | |
@time = time | |
@fps = fps | |
@timecode = [] | |
end | |
def map &block | |
parse_timecode | |
@tc.map &block | |
end | |
def parse_timecode | |
return if [email protected]? | |
raise IOError.new("Timecode file not exists") if !File.exists? @time | |
@timecode = File.readlines(@time).map do |line| | |
m = line.match /(\d+)\D+(\d+)/ | |
m.nil? ? nil : Timestamp.new(m[1], m[2]) | |
end.compact | |
end | |
def aac source:, target: nil, delay: 0 | |
parse_timecode | |
raise IOError if !File.exists? source | |
ext = File.extname(source) | |
base = File.basename(source, ext) | |
target = base + '.new.m4a' if target.nil? | |
if ext['.aac'] | |
base = '_' + base + '.aacmk' | |
ext = '.m4a' | |
mp4 = base + ext | |
sh "muxer -i #{source} -o #{mp4}" if !File.exists? mp4 | |
source = mp4 | |
end | |
# Produce slices | |
diff = 0 | |
name = '' | |
mp4_files = @timecode.map do |t| | |
from = t.from.to_time(fps: @fps) + diff | |
to = t.to_inc.to_time(fps: @fps) | |
duration = to - from | |
sh "mp4box -splitx #{from}:#{to} #{source}" | |
name = "#{base}_#{from.truncate}_#{to.truncate}#{ext}" | |
`mediainfo -f #{name} | grep Duration | head -n 1`[/ (\d+)\Z/] | |
actual_duration = $1.to_f / 1000.0 | |
diff = actual_duration - duration | |
puts 'Ideal: %.3f, Actual: %.3f, Diff: %.3f' % [duration, actual_duration, diff] | |
" -cat #{name} " | |
end | |
# Concatinating | |
mv target, target+'.bak' if File.exists? target | |
if mp4_files.size == 1 | |
mv name, target | |
else | |
sh "mp4box #{mp4_files.join} #{target}" | |
end | |
end | |
def avs source: 'main.avs', target: nil | |
parse_timecode | |
ext = File.extname(source) | |
base = File.basename(source, ext) | |
target = base + '.trim.avs' if target.nil? | |
File.write target, @timecode.map{ |t| "trim(#{t.from},#{t.to})" }.join(' + ') | |
end | |
def delogo source: 'main.avs', target: nil, fade: 0, offset1: 0, offset2: 0 | |
parse_timecode | |
ext = File.extname(source) | |
base = File.basename(source, ext) | |
target = base + '.delogo.avs' if target.nil? | |
current = 0 | |
File.open target, 'w' do |f| | |
@timecode.each do |tc| | |
length = tc.duration | |
f << 'EraseLOGO(logoFile' | |
f << ', fadein=%d, fadeout=%d' % [fade, fade] if fade != 0 | |
f << ', start=%d, end=%d)' % [current + offset1, current + length - offset2] | |
f << "\n" | |
current += length | |
end | |
end | |
end | |
def sub source: 'main.kingyubi.ass', target: nil, delay: 0 | |
parse_timecode | |
raise IOError if !File.exists? source | |
target = source.ext('.new.ass') if target.nil? | |
# Convert to Time Range | |
start_time = 0.0 | |
timerange = @timecode.map do |t| | |
s = t.from.to_time fps: @fps | |
e = t.to_inc.to_time fps: @fps | |
offset = start_time - s | |
start_time += e - s | |
{:s => s, :e => e, :o => offset} | |
end | |
subs = File.readlines(source).map { |l| SubtitleLine.new l } | |
subs.each do |s| | |
next if !s.dialog | |
catch :offset do | |
timerange.each do |t| | |
if s.between? from: t[:s], to: t[:e] | |
s.offset t[:o] | |
throw :offset | |
end | |
end | |
s.disable! | |
end | |
end | |
File.open(target, 'w') do |f| | |
subs.each { |s| f << s.to_s } | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment