require 'rubygems' require 'streamio-ffmpeg' require 'fileutils' require 'logger' require 'yaml' require 'peach' VID_FORMATS = %w[.avi .flv .mkv .mov .mp4] # Loads config file: @config=YAML.load(File.read("./config.yml")) # Logger setup stuff: @logger=Logger.new(@config[:log_location]) @logger.level=Logger::INFO @logger.info "\n New Run starting now......" @logger.info "Config is being used: #{@config}" # Check the file age: def file_age(name) (Time.now - File.ctime(name))/(24*3600) end def seconds_to_s(total_time) total_time=total_time.to_int return [total_time / 3600, total_time/ 60 % 60, total_time % 60].map { |t| t.to_s.rjust(2,'0') }.join(':') end # Creates a list (array) of all aged files: def get_aged_files(directory) out=[] Dir.foreach(directory){|file| next if file == '.' or file == '..' or file.start_with?('.') fileName=File.join(directory,file) if(File.file?(fileName)) then if VID_FORMATS.include? File.extname(file) then if(file_age(fileName)>=@config[:min_age_days]) then out< e @logger.error "Problem processing a video" @logger.error e end return nil end # Main function for conversion: def convert_file(original_video,filename) options={ video_codec: 'libx265', threads: @config[:threads], custom: "-preset #{@config[:preset]} -crf 25 -c:a copy".split } outFileName = get_base_name(filename) error_thrown=nil begin startTime=Time.now out = original_video.transcode(get_temp_filename(filename),options){ |progress| duration=Time.now-startTime remaining=(duration/progress)*(1-progress) if(remaining>99999999) then print "Progress converting #{filename.split('/').last} : #{(progress*100).round(1)}% \r" else print "Progress converting #{filename.split('/').last} : #{(progress*100).round(1)}% ETA is #{seconds_to_s(remaining)} \r" end } rescue StandardError => e error_thrown=e puts e.to_s end puts "Done with #{filename.split('\\').last}" if ( error_thrown ) @logger.error "A video file failed to transcode correctly" @logger.error error_thrown FileUtils.rm(get_temp_filename(filename)) if File.exists?(get_temp_filename(filename)) FileUtils.touch(get_temp_filename(filename)) File.write(get_temp_filename(filename), [ 'An exception occured while transocding this movie.', error_thrown ].join('\n')) elsif (out.size>original_video.size*@config[:max_new_file_size_ratio]) @logger.warn "A video file, after transcoding was not at least #{@config[:max_new_file_size_ratio]} the size of the origional (new: #{out.size} old: #{original_video.size}). Keeping origonal #{filename}" FileUtils.rm(get_temp_filename(filename)) FileUtils.touch(get_temp_filename(filename)) File.write(get_temp_filename(filename), "transcoded video not enough smaller than the origional.") return nil else FileUtils.mv(get_temp_filename(filename),"#{outFileName}.mp4") if filename!="#{outFileName}.mp4" then FileUtils.rm(filename) end return out end end def status(app) possible_files=get_aged_files(@config[:directory]) puts "There are a total of #{possible_files.size} files that may need to be converted." candidate_files= get_candidate_files(possible_files) puts "There are a total of #{candidate_files[:movies].size} files that have not been converted yet." puts "Total Duration: #{seconds_to_s(candidate_files[:runtime])}" end @total_processing_time=0 @processed_video_duration=0 def iterate possible_files=get_aged_files(@config[:directory]) @logger.info "There are a total of #{possible_files.size} files that may need to be converted." @logger.debug "Files to be checked: #{possible_files}" candidate_files= get_candidate_files(possible_files) @logger.info "There are a total of #{candidate_files[:movies].size} files that have not been converted yet." @logger.debug "Candidate Files that need to be re-encoded: #{candidate_files}" @logger.info "Total Duration: #{seconds_to_s(candidate_files[:runtime])}" remaining_runtime=candidate_files[:runtime] candidate_files[:movies].each_with_index do |file,index| @logger.info "Starting to transcode file #{index+1} of #{candidate_files[:movies].size}: #{file}" unless does_video_need_conversion?(file) @logger.info "Video already converted, scanning again" return true end startTime=Time.now video=FFMPEG::Movie.new(file) converted_video=safe_convert_file(video,file) duration=Time.now - startTime remaining_runtime-=video.duration if !converted_video.nil? then @total_processing_time+=duration @processed_video_duration+=video.duration end avg=@processed_video_duration/@total_processing_time @logger.info "Average videotime/walltime: #{avg} Estimated time remaining #{seconds_to_s(remaining_runtime/avg)}" end return false end while iterate do end