Skip to content

Instantly share code, notes, and snippets.

@bromine0x23
Created September 14, 2017 09:54
Show Gist options
  • Select an option

  • Save bromine0x23/927e596e2ccce46f1ad6d699adfc614c to your computer and use it in GitHub Desktop.

Select an option

Save bromine0x23/927e596e2ccce46f1ad6d699adfc614c to your computer and use it in GitHub Desktop.
kux.rb
#!ruby
#
# MKVToolNix required.
# https://mkvtoolnix.download/
#
require 'fileutils'
# YOUKU_DIR = 'D:\workspace\ruby\kux'
YOUKU_DIR = 'E:\Youku Files\download'
OUTPUT_DIR = 'E:\video\Youku'
TAG_TYPE = {
18 => 'SCRIPT',
9 => 'VIDEO',
8 => 'AUDIO'
}.freeze
def byte2ui24(bytes)
(bytes[0] << 16) + (bytes[1] << 8) + bytes[2]
end
def grab(input_filename, output_filename, debug: true)
File.open(input_filename, 'rb') do |input|
index = 0xe40000
count = 1
input.seek(index)
output = nil
data = "\x00" * 11
while data
if data == "\x00" * 11
if output
output.close
output = nil
end
index = (index + (1 << 18) - 1) >> 18 << 18
input.seek(index)
header = input.read(9 + 4)
index += 9 + 4
if header && header.chomp("\x00") != '' && header[0, 3] == 'FLV'
output = File.open(File.join(File.dirname(output_filename), "#{File.basename(output_filename, '.*')}_#{'%02d' % count}.flv"), 'wb')
STDOUT.printf("New flv(%02dp) @0x%08X\n", count, index)
STDOUT.flush
output.write(header)
count += 1
end
else
type, *length, _padding = data.unpack('CC3a7')
length = byte2ui24(length)
if debug
STDOUT.printf("TAG:%6s 0x%06X @0x%08X-0x%08X\n", TAG_TYPE[type], length, index, index + length + 4)
STDOUT.flush
end
data = input.read(length + 4) #data, pre tag size
index += length + 4
output.write(data)
end
data = input.read(11)
index += 11
if output
output.write(data)
output.flush
end
end
count - 1
end
end
def cleanup(filename, count)
1.upto(count) do |i|
File.delete(File.join(File.dirname(filename), "#{File.basename(filename, '.*')}_#{'%02d' % i}.flv"))
end
end
def make_mkv(filename, count)
args = ['-q']
args << '-o' << File.join(File.dirname(filename), "#{File.basename(filename, '.*')}.mkv")
args.concat(%w(--forced-track 0:no --forced-track 1:no))
args.concat(%W(-a 1 -d 0 -S -T --no-global-tags --no-chapters))
args << '(' << File.join(File.dirname(filename), "#{File.basename(filename, '.*')}_01.flv") << ')'
2.upto(count) do |i|
args.concat(%W(-a 1 -d 0 -S -T --no-global-tags --no-chapters +))
args << '(' << File.join(File.dirname(filename), "#{File.basename(filename, '.*')}_#{'%02d' % i}.flv") << ')'
end
args.concat(%w(--track-order 0:0,0:1 --append-to))
args << (1...count).map{|i| "#{i}:0:#{i-1}:0"}.join(',') + ',' + (1...count).map{|i| "#{i}:1:#{i-1}:1"}.join(',')
p args
system('mkvmerge', *args, out: STDOUT, err: STDERR)
end
def batch(input_directory, output_directory = input_directory)
unless Dir.exist?(input_directory)
puts 'YouKu directory not found.'
return
end
unless File.directory?(input_directory)
puts 'Given path is not a directory.'
return
end
# output_directory = File.dirname(output_directory)
FileUtils.makedirs(output_directory)
Dir.chdir(input_directory)
Dir.glob('*.kux') do |filename|
output_filename = File.join(output_directory, "#{File.basename(filename, '.*')}.flv")
puts "=> Processing #{filename}."
count = grab(filename, output_filename, debug: false)
if make_mkv(output_filename, count)
puts "<= Done #{filename} ."
else
puts "<= Failed #{filename}."
end
cleanup(output_filename, count)
end
end
batch(YOUKU_DIR, OUTPUT_DIR)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment