Skip to content

Instantly share code, notes, and snippets.

@jitingcn
Last active January 25, 2021 21:48
Show Gist options
  • Save jitingcn/efd3501825dd8cb812e984212c1f9dfc to your computer and use it in GitHub Desktop.
Save jitingcn/efd3501825dd8cb812e984212c1f9dfc to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'colorize'
require 'open3'
require 'json'
require 'tempfile'
def parse_info(filename)
data = JSON.load File.open(filename)
data['formats'].map do |format|
first_fragment = format['fragments'][0]
first_fragment_id = first_fragment['path'].match(/sq\/(.*)\/lmt\//)[1].to_i
duration = first_fragment['duration']
unless first_fragment_id.zero?
format['fragments'] = first_fragment_id.times.map do |i|
{ 'duration': duration, 'path': "sq/#{i}" }
end.push(*format['fragments'])
end
format
end
data
rescue StandardError => e
puts e.message
end
if ARGV.length.positive?
if ARGV.length == 1 # match youtube link
text = ARGV[0]
patten = %r{(?:https?:\/\/)?(?:youtu\.be\/|(?:www\.|m\.)?youtube\.com\/(?:watch|v|embed)(?:\.php)?(?:\?.*v=|\/))([a-zA-Z0-9\-_]+)}
if text.match?(patten)
puts "[download] #{text.match(patten)}".light_blue
begin
`youtube-dl -f 'bestvideo[ext=mp4],bestaudio/best' --skip-download --write-info-json -o temp '#{text.match(patten)}'`
info_json = Tempfile.open('ytb-', '/tmp')
info_json.write JSON.generate(parse_info('temp.info.json'), ascii_only: true)
info_json.close
`rm 'temp.info.json'`
`cp #{info_json.path} debug.json`
cmd = "youtube-dl --write-description -o '%(upload_date)s-%(title)s-%(id)s.%(ext)s' --buffer-size 32K --http-chunk-size 10M --external-downloader ffmpeg -f 'bestvideo[ext=mp4],bestaudio/best' --load-info-json '#{info_json.path}' 1>&2"
Thread.report_on_exception = false
_stdout, stderr, exit_status = Open3.capture3(cmd)
info_json.unlink
rescue Interrupt
puts 'Interrupt'.red.underline
info_json.unlink
exit
end
Thread.report_on_exception = true
exit unless exit_status.success?
puts "successful.".light_blue.blink
result = stderr.to_s.scan(/Destination:\ (.+)/).flatten
result = stderr.to_s.scan(/\[download\] (.+) has already been downloaded/).flatten if result.size.eql? 0
exit unless result.size.eql? 2
video = result[0]
audio = result[1]
else
video = Dir.glob(text + '.mp4').reject { |f| f.include? 'muxed' } [0]
audio = Dir.glob(text + '.*').select { |f| File.extname(f) == '.webm' or File.extname(f) == '.m4a' } [0]
end
elsif ARGV.length == 2
video = ARGV[0]
audio = ARGV[1]
end
filelist = [audio, video]
else
filelist = (Dir.glob('*.webm') + Dir.glob('*.mp4') + Dir.glob('*.m4a'))
.select {|f| !f.include? 'muxed' }
.select {|f| File.readable? f.to_s }
.sort
.reverse
puts filelist.size.to_s.light_blue
end
Dir.glob("*.description") do |f|
puts "rename #{f} to #{f}.txt"
`mv '#{f}' '#{f}.txt'`
end
filelist.each_slice(2) do |a, v|
unless File.basename(a, ".*") == File.basename(v, ".*") # &&
# (File.extname(audio) == ".webm" || File.extname(audio) == ".m4a") &&
# File.extname(video) == ".mp4"
puts "video: #{v}\naudio: #{a}" .light_blue
puts "error: mismatch input" .red .blink
exit
else
output = "#{v[0...-4]}-muxed.mp4"
end
`ffmpeg -hide_banner -y -i '#{v}' -i '#{a}' -c:v copy -c:a libfdk_aac -vbr 5 -ar 44100 '#{output}'`
unless $?.success?
puts 'error'.red.blink
exit
end
if File.exist? output.to_s
`rm '#{v}'`
puts "delete file: '#{v}' success".colorize(:light_blue)
`rm '#{a}'`
puts "delete file: '#{a}' success".colorize(:light_blue)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment