Skip to content

Instantly share code, notes, and snippets.

@epk
Last active November 24, 2019 17:35
Show Gist options
  • Save epk/4eb34caf388891bddf20b5846fff85a8 to your computer and use it in GitHub Desktop.
Save epk/4eb34caf388891bddf20b5846fff85a8 to your computer and use it in GitHub Desktop.
# frozen_string_literal: true
require 'net/http'
require 'fileutils'
require 'tempfile'
require 'open3'
require 'set'
require 'parallel'
class Panopto
class << self
def download_chunks(endpoint, video_name)
uri = URI.parse(endpoint)
@base_request_uri = uri.request_uri.split("/")[0...-1]
@connection = Net::HTTP.new(uri.host, uri.port).tap do |client|
client.use_ssl = uri.scheme == 'https'
end
chunks = find_number_of_chunks(0, 1000)
FileUtils.mkdir_p(File.join("src", video_name))
(0..chunks).each do |i|
chunk = "#{format('%05d', i)}.ts"
request_uri = @base_request_uri.dup
request_uri << chunk
request_uri = request_uri.join("/")
if File.file?(File.join("src", video_name, chunk))
next
else
request = Net::HTTP::Get.new(request_uri)
response = @connection.request(request)
code = response.code.to_i
if code == 200
File.open(File.join("src", video_name, chunk), "w") { |file| file.puts response.body }
end
end
puts("#{video_name}: #{i}/#{chunks} downloaded")
end
end
def concat_chunks(video_name)
return if File.file?("#{video_name.chomp}.mp4")
list = []
files = Dir.entries(File.join("src", video_name)).reject { |f| File.directory?(f) }
files.sort.each do |file|
list << "file '#{File.expand_path(File.join('src', video_name, file))}'"
end
FileUtils.rm("list.txt") if File.file?("list.txt")
File.open("list.txt", "w") { |file| file.puts list.join("\n") }
Open3.popen3("ffmpeg",
"-safe", "0",
"-f", "concat", "-i", "list.txt",
"-c", "copy", "#{video_name.chomp}.mp4") do |_stdin, stdout, _stderr, _thread|
puts stdout.read.chomp
end
true
ensure
FileUtils.rm("list.txt") if File.file?("list.txt")
end
def transcribe(video_name)
# autosub -i Lecture_1.mp4 -S en-ca
Open3.popen3("autosub",
"-i", "#{video_name.chomp}.mp4",
"-S", "en-ca") do |_stdin, stdout, _stderr, _thread|
puts stdout.read.chomp
end
# ffmpeg -i infile.mp4 -i infile.srt -c copy -c:s mov_text outfile.mp4
Open3.popen3("ffmpeg",
"-i", "#{video_name.chomp}.mp4",
"-i", "#{video_name.chomp}.en-ca.srt",
"-c", "copy",
"-c:s", "mov_text",
"#{video_name.chomp}_subtitled.mp4") do |_stdin, stdout, _stderr, _thread|
puts stdout.read.chomp
end
true
end
private
def find_number_of_chunks(lower, upper)
mid = lower + (upper - lower) / 2
valid = poll_endpoint_for_chunk(mid)
if valid && !poll_endpoint_for_chunk(mid + 1)
return mid
elsif valid && poll_endpoint_for_chunk(mid + 1)
return find_number_of_chunks(mid, upper)
else
return find_number_of_chunks(lower, mid)
end
end
def poll_endpoint_for_chunk(counter)
chunk = "#{format('%05d', counter)}.ts"
request_uri = @base_request_uri.dup
request_uri << chunk
request_uri = request_uri.join("/")
request = Net::HTTP::Head.new(request_uri)
response = @connection.request(request)
code = response.code.to_i
code == 200
end
end
end
begin
list = []
if list.to_set.length != list.length
raise("Duplicate items in array")
end
Parallel.each_with_index(list) do |url, index|
Panopto.download_chunks(url, "Lecture_#{index + 1}")
end
list.each_with_index do |_, index|
Panopto.concat_chunks("Lecture_#{index + 1}")
end
list.each_with_index do |_, index|
Panopto.transcribe("Lecture_#{index + 1}")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment