diff --git a/record-and-playback/core/scripts/cleanup.rb b/record-and-playback/core/scripts/cleanup.rb index 120b305be33a7c5a8e7cbcef373cd2823df44206..1db8720473b2151f2ee32b05f0c20e032211afc8 100755 --- a/record-and-playback/core/scripts/cleanup.rb +++ b/record-and-playback/core/scripts/cleanup.rb @@ -27,54 +27,54 @@ RECORDING_DIR="/var/bigbluebutton/recording" def cleanProcessedFiles(path) - redis=Redis.new - # get the pastday - pastday=Time.new-(3600*24) - puts "Cleaning out conferences before #{pastday}" - - (Dir.entries(path) - ['.','..']).each do - |playback| - (Dir.entries(path+"/#{playback}") - ['.','..']).each do - |meeting| - - modtime = File.mtime(path+"/#{playback}/#{meeting}") - dif=modtime <=> pastday - # 1 represents all the recording upto the pastday - if dif != 1 - puts "Meeting: #{meeting}" - #Deleting Processed Dir - puts "Checking record and ingest directories..." - - puts "Deleting *.done files..." - FileUtils.rm_rf RECORDING_DIR+"/status/recorded/#{meeting}.done" - FileUtils.rm_rf RECORDING_DIR+"/status/archived/#{meeting}.done" - FileUtils.rm_rf RECORDING_DIR+"/status/processed/#{meeting}-#{playback}.done" - - puts "Deleting processed directories..." - if(File.directory?(RECORDING_DIR+"/process/#{playback}/#{meeting}")) - FileUtils.rm_rf RECORDING_DIR+"/process/#{playback}/#{meeting}" - end - if(File.directory?(RECORDING_DIR+"/publish/#{playback}/#{meeting}")) - FileUtils.rm_rf RECORDING_DIR+"/publish/#{playback}/#{meeting}" - end - - #Deleting Redis Keys - puts "Checking redis keys..." - if( redis.exists("meeting:#{meeting}:recordings")) - len= redis.llen("meeting:#{meeting}:recordings") - range= redis.lrange("meeting:#{meeting}:recordings",0,len) - range.each do - |msgid| - redis.del("recording:#{meeting}:#{msgid}") - end - puts "Deleting Redis Keys for #{meeting}" - redis.del("meeting:#{meeting}:recordings") - end - end - - end - - end + redis=Redis.new + # get the pastday + pastday=Time.new-(3600*24) + puts "Cleaning out conferences before #{pastday}" + + (Dir.entries(path) - ['.','..']).each do + |playback| + (Dir.entries(path+"/#{playback}") - ['.','..']).each do + |meeting| + + modtime = File.mtime(path+"/#{playback}/#{meeting}") + dif=modtime <=> pastday + # 1 represents all the recording upto the pastday + if dif != 1 + puts "Meeting: #{meeting}" + #Deleting Processed Dir + puts "Checking record and ingest directories..." + + puts "Deleting *.done files..." + FileUtils.rm_rf RECORDING_DIR+"/status/recorded/#{meeting}.done" + FileUtils.rm_rf RECORDING_DIR+"/status/archived/#{meeting}.done" + FileUtils.rm_rf RECORDING_DIR+"/status/processed/#{meeting}-#{playback}.done" + + puts "Deleting processed directories..." + if(File.directory?(RECORDING_DIR+"/process/#{playback}/#{meeting}")) + FileUtils.rm_rf RECORDING_DIR+"/process/#{playback}/#{meeting}" + end + if(File.directory?(RECORDING_DIR+"/publish/#{playback}/#{meeting}")) + FileUtils.rm_rf RECORDING_DIR+"/publish/#{playback}/#{meeting}" + end + + #Deleting Redis Keys + puts "Checking redis keys..." + if( redis.exists("meeting:#{meeting}:recordings")) + len= redis.llen("meeting:#{meeting}:recordings") + range= redis.lrange("meeting:#{meeting}:recordings",0,len) + range.each do + |msgid| + redis.del("recording:#{meeting}:#{msgid}") + end + puts "Deleting Redis Keys for #{meeting}" + redis.del("meeting:#{meeting}:recordings") + end + end + + end + + end end diff --git a/record-and-playback/core/scripts/rap-worker.rb b/record-and-playback/core/scripts/rap-worker.rb index c299fad126d5035a78a9799c64f612211f11b931..5e995d31c6d42382466c5550341799dec05a61c2 100755 --- a/record-and-playback/core/scripts/rap-worker.rb +++ b/record-and-playback/core/scripts/rap-worker.rb @@ -36,7 +36,7 @@ def archive_recorded_meeting(recording_dir) recorded_done_files.each do |recorded_done| match = /([^\/]*).done$/.match(recorded_done) meeting_id = match[1] - + if File.mtime(recorded_done) + ARCHIVE_DELAY_SECONDS > Time.now BigBlueButton.logger.info("Temporarily skipping #{meeting_id} for Red5 race workaround") next @@ -359,4 +359,4 @@ rescue Exception => e e.backtrace.each do |traceline| BigBlueButton.logger.error(traceline) end -end +end diff --git a/record-and-playback/presentation/scripts/process/presentation.rb b/record-and-playback/presentation/scripts/process/presentation.rb index ed81c3f7e4f1675a4081604b85afeed00aaa8821..10e1634709842aca6647550ef4f62dba342050c8 100755 --- a/record-and-playback/presentation/scripts/process/presentation.rb +++ b/record-and-playback/presentation/scripts/process/presentation.rb @@ -54,32 +54,32 @@ if not FileTest.directory?(target_dir) BigBlueButton.logger = logger BigBlueButton.logger.info("Processing script presentation.rb") FileUtils.mkdir_p target_dir - + begin # Create a copy of the raw archives temp_dir = "#{target_dir}/temp" FileUtils.mkdir_p temp_dir FileUtils.cp_r(raw_archive_dir, temp_dir) - + BigBlueButton::AudioProcessor.process("#{temp_dir}/#{meeting_id}", "#{target_dir}/audio") events_xml = "#{temp_dir}/#{meeting_id}/events.xml" FileUtils.cp(events_xml, target_dir) - + presentation_dir = "#{temp_dir}/#{meeting_id}/presentation" presentations = BigBlueButton::Presentation.get_presentations(events_xml) - + processed_pres_dir = "#{target_dir}/presentation" FileUtils.mkdir_p processed_pres_dir - + presentations.each do |pres| pres_dir = "#{presentation_dir}/#{pres}" num_pages = BigBlueButton::Presentation.get_number_of_pages_for(pres_dir) - + target_pres_dir = "#{processed_pres_dir}/#{pres}" FileUtils.mkdir_p target_pres_dir FileUtils.mkdir_p "#{target_pres_dir}/textfiles" - + images=Dir.glob("#{pres_dir}/#{pres}.{jpg,jpeg,png,gif,JPG,JPEG,PNG,GIF}") if images.empty? pres_name = "#{pres_dir}/#{pres}" @@ -113,7 +113,7 @@ if not FileTest.directory?(target_dir) BigBlueButton.execute(command) end end - + if !Dir["#{raw_archive_dir}/video/*"].empty? or (presentation_props['include_deskshare'] and !Dir["#{raw_archive_dir}/deskshare/*"].empty?) width = presentation_props['video_output_width'] height = presentation_props['video_output_height'] @@ -128,13 +128,13 @@ if not FileTest.directory?(target_dir) process_done.write("Processed #{meeting_id}") process_done.close #else -# BigBlueButton.logger.debug("Skipping #{meeting_id} as it has already been processed.") +# BigBlueButton.logger.debug("Skipping #{meeting_id} as it has already been processed.") rescue Exception => e BigBlueButton.logger.error(e.message) - e.backtrace.each do |traceline| - BigBlueButton.logger.error(traceline) - end - exit 1 + e.backtrace.each do |traceline| + BigBlueButton.logger.error(traceline) + end + exit 1 end end - + diff --git a/record-and-playback/presentation/scripts/publish/presentation.rb b/record-and-playback/presentation/scripts/publish/presentation.rb index e26a894c798b84ea914afd638416270f9c051bbf..e0fbfa0c4d75703c0bc7dd687bc00dd2fb83a538 100755 --- a/record-and-playback/presentation/scripts/publish/presentation.rb +++ b/record-and-playback/presentation/scripts/publish/presentation.rb @@ -36,92 +36,92 @@ class String end def processPanAndZooms - #Create panzooms.xml - BigBlueButton.logger.info("Creating panzooms.xml") - $panzooms_xml = Nokogiri::XML::Builder.new do |xml| - $xml = xml - $xml.recording('id' => 'panzoom_events') do - h_ratio_prev = nil - w_ratio_prev = nil - x_prev = nil - y_prev = nil - timestamp_orig_prev = nil - timestamp_prev = nil - last_time = nil - if $panzoom_events.empty? - BigBlueButton.logger.info("No panzoom events; old recording?") - BigBlueButton.logger.info("Synthesizing a panzoom event") - if !$slides_events.empty? - timestamp_orig = $slides_events.first[:timestamp].to_f - # make sure this is scheduled *after* the slide is shown. Dunno if needed. - timestamp_orig += 1000 - timestamp = ( translateTimestamp(timestamp_orig) / 1000 ).round(1) - $xml.event(:timestamp => timestamp, :orig => timestamp_orig) do - $xml.viewBox "0 0 #{$vbox_width} #{$vbox_height}" - end - timestamp_orig_prev = timestamp_orig - timestamp_prev = timestamp - h_ratio_prev = 100 - w_ratio_prev = 100 - x_prev = 0 - y_prev = 0 - else - BigBlueButton.logger.info("Couldn't find any slides! panzooms will be empty.") - end - else - last_time = $panzoom_events.last[:timestamp].to_f - end - $panzoom_events.each do |panZoomEvent| - # Get variables - timestamp_orig = panZoomEvent[:timestamp].to_f - - timestamp = ( translateTimestamp(timestamp_orig) / 1000 ).round(1) - h_ratio = panZoomEvent.xpath(".//heightRatio")[0].text() - w_ratio = panZoomEvent.xpath(".//widthRatio")[0].text() - x = panZoomEvent.xpath(".//xOffset")[0].text() - y = panZoomEvent.xpath(".//yOffset")[0].text() - - if(timestamp_prev == timestamp) - if(timestamp_orig == last_time) - if(h_ratio && w_ratio && x && y) - $xml.event(:timestamp => timestamp, :orig => timestamp_orig) do - $ss.each do |key,val| - $val = val - if key === timestamp - $vbox_width = $val[0] - $vbox_height = $val[1] - end - end - $xml.viewBox "#{($vbox_width-((1-((x.to_f.abs)*$magic_mystery_number/100.0))*$vbox_width))} #{($vbox_height-((1-((y.to_f.abs)*$magic_mystery_number/100.0))*$vbox_height)).round(2)} #{((w_ratio.to_f/100.0)*$vbox_width).round(1)} #{((h_ratio.to_f/100.0)*$vbox_height).round(1)}" - end - end - end - # do nothing because playback can't react that fast - else - if(h_ratio_prev && w_ratio_prev && x_prev && y_prev) - $xml.event(:timestamp => timestamp_prev, :orig => timestamp_orig_prev) do - $ss.each do |key,val| - $val = val - if key === timestamp_prev - $vbox_width = $val[0] - $vbox_height = $val[1] - end - end - $xml.viewBox "#{($vbox_width-((1-((x_prev.to_f.abs)*$magic_mystery_number/100.0))*$vbox_width))} #{($vbox_height-((1-((y_prev.to_f.abs)*$magic_mystery_number/100.0))*$vbox_height)).round(2)} #{((w_ratio_prev.to_f/100.0)*$vbox_width).round(1)} #{((h_ratio_prev.to_f/100.0)*$vbox_height).round(1)}" - end - end - end - timestamp_prev = timestamp - timestamp_orig_prev = timestamp_orig - h_ratio_prev = h_ratio - w_ratio_prev = w_ratio - x_prev = x - y_prev = y - end - $xml.event(:timestamp => timestamp_prev, :orig => timestamp_orig_prev) do - $ss.each do |key,val| - $val = val - if key === timestamp_prev + #Create panzooms.xml + BigBlueButton.logger.info("Creating panzooms.xml") + $panzooms_xml = Nokogiri::XML::Builder.new do |xml| + $xml = xml + $xml.recording('id' => 'panzoom_events') do + h_ratio_prev = nil + w_ratio_prev = nil + x_prev = nil + y_prev = nil + timestamp_orig_prev = nil + timestamp_prev = nil + last_time = nil + if $panzoom_events.empty? + BigBlueButton.logger.info("No panzoom events; old recording?") + BigBlueButton.logger.info("Synthesizing a panzoom event") + if !$slides_events.empty? + timestamp_orig = $slides_events.first[:timestamp].to_f + # make sure this is scheduled *after* the slide is shown. Dunno if needed. + timestamp_orig += 1000 + timestamp = ( translateTimestamp(timestamp_orig) / 1000 ).round(1) + $xml.event(:timestamp => timestamp, :orig => timestamp_orig) do + $xml.viewBox "0 0 #{$vbox_width} #{$vbox_height}" + end + timestamp_orig_prev = timestamp_orig + timestamp_prev = timestamp + h_ratio_prev = 100 + w_ratio_prev = 100 + x_prev = 0 + y_prev = 0 + else + BigBlueButton.logger.info("Couldn't find any slides! panzooms will be empty.") + end + else + last_time = $panzoom_events.last[:timestamp].to_f + end + $panzoom_events.each do |panZoomEvent| + # Get variables + timestamp_orig = panZoomEvent[:timestamp].to_f + + timestamp = ( translateTimestamp(timestamp_orig) / 1000 ).round(1) + h_ratio = panZoomEvent.xpath(".//heightRatio")[0].text() + w_ratio = panZoomEvent.xpath(".//widthRatio")[0].text() + x = panZoomEvent.xpath(".//xOffset")[0].text() + y = panZoomEvent.xpath(".//yOffset")[0].text() + + if(timestamp_prev == timestamp) + if(timestamp_orig == last_time) + if(h_ratio && w_ratio && x && y) + $xml.event(:timestamp => timestamp, :orig => timestamp_orig) do + $ss.each do |key,val| + $val = val + if key === timestamp + $vbox_width = $val[0] + $vbox_height = $val[1] + end + end + $xml.viewBox "#{($vbox_width-((1-((x.to_f.abs)*$magic_mystery_number/100.0))*$vbox_width))} #{($vbox_height-((1-((y.to_f.abs)*$magic_mystery_number/100.0))*$vbox_height)).round(2)} #{((w_ratio.to_f/100.0)*$vbox_width).round(1)} #{((h_ratio.to_f/100.0)*$vbox_height).round(1)}" + end + end + end + # do nothing because playback can't react that fast + else + if(h_ratio_prev && w_ratio_prev && x_prev && y_prev) + $xml.event(:timestamp => timestamp_prev, :orig => timestamp_orig_prev) do + $ss.each do |key,val| + $val = val + if key === timestamp_prev + $vbox_width = $val[0] + $vbox_height = $val[1] + end + end + $xml.viewBox "#{($vbox_width-((1-((x_prev.to_f.abs)*$magic_mystery_number/100.0))*$vbox_width))} #{($vbox_height-((1-((y_prev.to_f.abs)*$magic_mystery_number/100.0))*$vbox_height)).round(2)} #{((w_ratio_prev.to_f/100.0)*$vbox_width).round(1)} #{((h_ratio_prev.to_f/100.0)*$vbox_height).round(1)}" + end + end + end + timestamp_prev = timestamp + timestamp_orig_prev = timestamp_orig + h_ratio_prev = h_ratio + w_ratio_prev = w_ratio + x_prev = x + y_prev = y + end + $xml.event(:timestamp => timestamp_prev, :orig => timestamp_orig_prev) do + $ss.each do |key,val| + $val = val + if key === timestamp_prev $vbox_width = $val[0] $vbox_height = $val[1] end @@ -129,312 +129,312 @@ def processPanAndZooms $xml.viewBox "#{($vbox_width-((1-((x_prev.to_f.abs)*$magic_mystery_number/100.0))*$vbox_width))} #{($vbox_height-((1-((y_prev.to_f.abs)*$magic_mystery_number/100.0))*$vbox_height)).round(2)} #{((w_ratio_prev.to_f/100.0)*$vbox_width).round(1)} #{((h_ratio_prev.to_f/100.0)*$vbox_height).round(1)}" end - end - end - BigBlueButton.logger.info("Finished creating panzooms.xml") + end + end + BigBlueButton.logger.info("Finished creating panzooms.xml") end def processCursorEvents - BigBlueButton.logger.info("Processing cursor events") - $cursor_xml = Nokogiri::XML::Builder.new do |xml| - $xml = xml - $xml.recording('id' => 'cursor_events') do - x_prev = nil - y_prev = nil - timestamp_orig_prev = nil - timestamp_prev = nil - if(!$cursor_events.empty?) - last_time = $cursor_events.last[:timestamp].to_f - $cursor_events.each do |cursorEvent| - timestamp_orig = cursorEvent[:timestamp].to_f - timestamp = ( translateTimestamp(timestamp_orig) / 1000 ).round(1) - - x = cursorEvent.xpath(".//xOffset")[0].text() - y = cursorEvent.xpath(".//yOffset")[0].text() - if(timestamp_prev == timestamp) - - else - if(x_prev && y_prev) - $ss.each do |key,val| - $val = val - if key === timestamp_prev - $vbox_width = $val[0]/2 # because the image size is twice as big as the viewbox - $vbox_height = $val[1]/2 # because the image size is twice as big as the viewbox - end - end - xPoint = ($vbox_width.to_f*x.to_f).round(1) - yPoint = ($vbox_height.to_f*y.to_f).round(1) - if xPoint < 800 and yPoint < 600 and xPoint > 0 and yPoint > 0 - $xml.event(:timestamp => timestamp_prev, :orig => timestamp_orig_prev) do - $xml.cursor "#{xPoint} #{yPoint}" - end - end - end - end - timestamp_prev = timestamp - timestamp_orig_prev = timestamp_orig - x_prev = x - y_prev = y - end - end - end - end - BigBlueButton.logger.info("Finished processing cursor events") + BigBlueButton.logger.info("Processing cursor events") + $cursor_xml = Nokogiri::XML::Builder.new do |xml| + $xml = xml + $xml.recording('id' => 'cursor_events') do + x_prev = nil + y_prev = nil + timestamp_orig_prev = nil + timestamp_prev = nil + if(!$cursor_events.empty?) + last_time = $cursor_events.last[:timestamp].to_f + $cursor_events.each do |cursorEvent| + timestamp_orig = cursorEvent[:timestamp].to_f + timestamp = ( translateTimestamp(timestamp_orig) / 1000 ).round(1) + + x = cursorEvent.xpath(".//xOffset")[0].text() + y = cursorEvent.xpath(".//yOffset")[0].text() + if(timestamp_prev == timestamp) + + else + if(x_prev && y_prev) + $ss.each do |key,val| + $val = val + if key === timestamp_prev + $vbox_width = $val[0]/2 # because the image size is twice as big as the viewbox + $vbox_height = $val[1]/2 # because the image size is twice as big as the viewbox + end + end + xPoint = ($vbox_width.to_f*x.to_f).round(1) + yPoint = ($vbox_height.to_f*y.to_f).round(1) + if xPoint < 800 and yPoint < 600 and xPoint > 0 and yPoint > 0 + $xml.event(:timestamp => timestamp_prev, :orig => timestamp_orig_prev) do + $xml.cursor "#{xPoint} #{yPoint}" + end + end + end + end + timestamp_prev = timestamp + timestamp_orig_prev = timestamp_orig + x_prev = x + y_prev = y + end + end + end + end + BigBlueButton.logger.info("Finished processing cursor events") end def processClearEvents - # process all the cleared pages events. - $clear_page_events.each do |clearEvent| - #Retrieve time, page and presentation. - clearTime = clearEvent[:timestamp].to_f - #clearTime = ( clearEvent[:timestamp].to_f / 1000 ).round(1) - $pageCleared = clearEvent.xpath(".//pageNumber")[0].text() - slideFolder = clearEvent.xpath(".//presentation")[0].text() - if $version_atleast_0_9_0 - $clearPageTimes[($prev_clear_time..clearTime)] = - [$pageCleared, $canvas_number, "presentation/#{slideFolder}/slide-#{$pageCleared.to_i + 1}.png", nil] - else - $clearPageTimes[($prev_clear_time..clearTime)] = - [$pageCleared, $canvas_number, "presentation/#{slideFolder}/slide-#{$pageCleared}.png", nil] - end - $prev_clear_time = clearTime - $canvas_number+=1 - end + # process all the cleared pages events. + $clear_page_events.each do |clearEvent| + #Retrieve time, page and presentation. + clearTime = clearEvent[:timestamp].to_f + #clearTime = ( clearEvent[:timestamp].to_f / 1000 ).round(1) + $pageCleared = clearEvent.xpath(".//pageNumber")[0].text() + slideFolder = clearEvent.xpath(".//presentation")[0].text() + if $version_atleast_0_9_0 + $clearPageTimes[($prev_clear_time..clearTime)] = + [$pageCleared, $canvas_number, "presentation/#{slideFolder}/slide-#{$pageCleared.to_i + 1}.png", nil] + else + $clearPageTimes[($prev_clear_time..clearTime)] = + [$pageCleared, $canvas_number, "presentation/#{slideFolder}/slide-#{$pageCleared}.png", nil] + end + $prev_clear_time = clearTime + $canvas_number+=1 + end end def processUndoEvents - # Processing the undo events, creating/filling a hashmap called "undos". - BigBlueButton.logger.info("Process undo events.") - $undo_events.each do |undo| - closest_shape = nil # Initialize as nil to prime the loop. - t = undo[:timestamp].to_f - $shape_events.each do |shape| - # The undo cannot be for a shape that hasn't been drawn yet. - if shape[:timestamp].to_f < t - # It must be the closest shape drawn that hasn't already been undone. - if (closest_shape == nil) || (shape[:timestamp].to_f > closest_shape[:timestamp].to_f) - # It cannot be an undo for another shape already. - if !($undos.has_key? shape) - # Must be part of this presentation of course - if shape.xpath(".//pageNumber")[0].text() == undo.xpath(".//pageNumber")[0].text() - # Must be a shape in this page too. - if shape.xpath(".//presentation")[0].text() == undo.xpath(".//presentation")[0].text() - if ((shape.xpath(".//type")[0].text() == "rectangle") || (shape.xpath(".//type")[0].text() == "ellipse")) - shape_already_processed = false - if($undos.length == 0) - shape_already_processed = false - else - $undos.each do |u, v| - if shape.xpath(".//dataPoints")[0].text().split(",")[0] == u.xpath(".//dataPoints")[0].text().split(",")[0] - if shape.xpath(".//dataPoints")[0].text().split(",")[1] == u.xpath(".//dataPoints")[0].text().split(",")[1] - shape_already_processed = true - end - end - end - end - if !(shape_already_processed) - closest_shape = shape - end - else - closest_shape = shape - end - end - end - end - end - end - end - if(closest_shape != nil) - $undos[closest_shape] = undo[:timestamp] - end - end - - $undos_temp = {} - $undos.each do |un, val| - $undos_temp[ un[:timestamp] ] = val - end - $undos = $undos_temp - BigBlueButton.logger.info("Undos: #{$undos}") + # Processing the undo events, creating/filling a hashmap called "undos". + BigBlueButton.logger.info("Process undo events.") + $undo_events.each do |undo| + closest_shape = nil # Initialize as nil to prime the loop. + t = undo[:timestamp].to_f + $shape_events.each do |shape| + # The undo cannot be for a shape that hasn't been drawn yet. + if shape[:timestamp].to_f < t + # It must be the closest shape drawn that hasn't already been undone. + if (closest_shape == nil) || (shape[:timestamp].to_f > closest_shape[:timestamp].to_f) + # It cannot be an undo for another shape already. + if !($undos.has_key? shape) + # Must be part of this presentation of course + if shape.xpath(".//pageNumber")[0].text() == undo.xpath(".//pageNumber")[0].text() + # Must be a shape in this page too. + if shape.xpath(".//presentation")[0].text() == undo.xpath(".//presentation")[0].text() + if ((shape.xpath(".//type")[0].text() == "rectangle") || (shape.xpath(".//type")[0].text() == "ellipse")) + shape_already_processed = false + if($undos.length == 0) + shape_already_processed = false + else + $undos.each do |u, v| + if shape.xpath(".//dataPoints")[0].text().split(",")[0] == u.xpath(".//dataPoints")[0].text().split(",")[0] + if shape.xpath(".//dataPoints")[0].text().split(",")[1] == u.xpath(".//dataPoints")[0].text().split(",")[1] + shape_already_processed = true + end + end + end + end + if !(shape_already_processed) + closest_shape = shape + end + else + closest_shape = shape + end + end + end + end + end + end + end + if(closest_shape != nil) + $undos[closest_shape] = undo[:timestamp] + end + end + + $undos_temp = {} + $undos.each do |un, val| + $undos_temp[ un[:timestamp] ] = val + end + $undos = $undos_temp + BigBlueButton.logger.info("Undos: #{$undos}") end def processClearImages - BigBlueButton.logger.info("Put image numbers in clearPageTimes") - $slides_compiled.each do |key, val| - $clearPageTimes.each do |cpt, pgCanvasUrl| - # check if the src of the slide matches the url of the clear event - if key[0] == pgCanvasUrl[2] - # put the image number into the $clearPageTimes - pgCanvasUrl[3] = "image#{val[2].to_i}" - end - end - end + BigBlueButton.logger.info("Put image numbers in clearPageTimes") + $slides_compiled.each do |key, val| + $clearPageTimes.each do |cpt, pgCanvasUrl| + # check if the src of the slide matches the url of the clear event + if key[0] == pgCanvasUrl[2] + # put the image number into the $clearPageTimes + pgCanvasUrl[3] = "image#{val[2].to_i}" + end + end + end end def storePencilShape - $pencil_count = $pencil_count + 1 # always update the line count! - $global_shape_count += 1 - $xml.g(:class => :shape, :id=>"draw#{$global_shape_count}", :timestamp => $shapeCreationTime, :undo => $shapeUndoTime, :shape =>"line#{$pencil_count}", :style => "stroke:\##{$colour_hex}; stroke-width:#{$shapeThickness}; visibility:hidden; stroke-linecap: round; ") do - for i in (0...($shapeDataPoints.length/2)-1) do - $xml.line(:x1 => (($shapeDataPoints[i*2].to_f)/100)*$vbox_width, :y1 => (($shapeDataPoints[(i*2)+1].to_f)/100)*$vbox_height, :x2 => (($shapeDataPoints[(i*2)+2].to_f)/100)*$vbox_width, :y2 => (($shapeDataPoints[(i*2)+3].to_f)/100)*$vbox_height) - end - end + $pencil_count = $pencil_count + 1 # always update the line count! + $global_shape_count += 1 + $xml.g(:class => :shape, :id=>"draw#{$global_shape_count}", :timestamp => $shapeCreationTime, :undo => $shapeUndoTime, :shape =>"line#{$pencil_count}", :style => "stroke:\##{$colour_hex}; stroke-width:#{$shapeThickness}; visibility:hidden; stroke-linecap: round; ") do + for i in (0...($shapeDataPoints.length/2)-1) do + $xml.line(:x1 => (($shapeDataPoints[i*2].to_f)/100)*$vbox_width, :y1 => (($shapeDataPoints[(i*2)+1].to_f)/100)*$vbox_height, :x2 => (($shapeDataPoints[(i*2)+2].to_f)/100)*$vbox_width, :y2 => (($shapeDataPoints[(i*2)+3].to_f)/100)*$vbox_height) + end + end end def storeLineShape - if(($originalOriginX == (($shapeDataPoints[0].to_f)/100)*$vbox_width) && ($originalOriginY == (($shapeDataPoints[1].to_f)/100)*$vbox_height)) - # do not update the line count - else - $line_count = $line_count + 1 - end - $global_shape_count += 1 - $xml.g(:class => :shape, :id => "draw#{$global_shape_count}", :timestamp => $shapeCreationTime, :undo => $shapeUndoTime, :shape => "line#{$line_count}", :style => "stroke:\##{$colour_hex}; stroke-width:#{$shapeThickness}; visibility:hidden; fill:none") do - - $originX = (($shapeDataPoints[0].to_f)/100)*$vbox_width - $originY = (($shapeDataPoints[1].to_f)/100)*$vbox_height - endPointX = (($shapeDataPoints[2].to_f)/100)*$vbox_width - endPointY = (($shapeDataPoints[3].to_f)/100)*$vbox_height - - $originalOriginX = $originX - $originalOriginY = $originY - - $xml.line(:x1 => $originX, :y1 => $originY, :x2 => endPointX, :y2 => endPointY ) - $prev_time = $shapeCreationTime - end + if(($originalOriginX == (($shapeDataPoints[0].to_f)/100)*$vbox_width) && ($originalOriginY == (($shapeDataPoints[1].to_f)/100)*$vbox_height)) + # do not update the line count + else + $line_count = $line_count + 1 + end + $global_shape_count += 1 + $xml.g(:class => :shape, :id => "draw#{$global_shape_count}", :timestamp => $shapeCreationTime, :undo => $shapeUndoTime, :shape => "line#{$line_count}", :style => "stroke:\##{$colour_hex}; stroke-width:#{$shapeThickness}; visibility:hidden; fill:none") do + + $originX = (($shapeDataPoints[0].to_f)/100)*$vbox_width + $originY = (($shapeDataPoints[1].to_f)/100)*$vbox_height + endPointX = (($shapeDataPoints[2].to_f)/100)*$vbox_width + endPointY = (($shapeDataPoints[3].to_f)/100)*$vbox_height + + $originalOriginX = $originX + $originalOriginY = $originY + + $xml.line(:x1 => $originX, :y1 => $originY, :x2 => endPointX, :y2 => endPointY ) + $prev_time = $shapeCreationTime + end end def storeRectShape - if(($originalOriginX == (($shapeDataPoints[0].to_f)/100)*$vbox_width) && ($originalOriginY == (($shapeDataPoints[1].to_f)/100)*$vbox_height)) - # do not update the rectangle count - else - $rectangle_count = $rectangle_count + 1 - end - $global_shape_count += 1 - $xml.g(:class => :shape, :id => "draw#{$global_shape_count}", :timestamp => $shapeCreationTime, :undo => $shapeUndoTime, :shape => "rect#{$rectangle_count}", :style => "stroke:\##{$colour_hex}; stroke-width:#{$shapeThickness}; visibility:hidden; fill:none") do - $originX = (($shapeDataPoints[0].to_f)/100)*$vbox_width - $originY = (($shapeDataPoints[1].to_f)/100)*$vbox_height - $originalOriginX = $originX - $originalOriginY = $originY - rectWidth = (($shapeDataPoints[2].to_f - $shapeDataPoints[0].to_f)/100)*$vbox_width - rectHeight = (($shapeDataPoints[3].to_f - $shapeDataPoints[1].to_f)/100)*$vbox_height - - # Cannot have a negative height or width so we adjust - if(rectHeight < 0) - $originY = $originY + rectHeight - rectHeight = rectHeight.abs - end - if(rectWidth < 0) - $originX = $originX + rectWidth - rectWidth = rectWidth.abs - end - if $is_square == "true" - #width of the square as reference - $xml.rect(:x => $originX, :y => $originY, :width => rectWidth, :height => rectWidth) - else - $xml.rect(:x => $originX, :y => $originY, :width => rectWidth, :height => rectHeight) - end - $prev_time = $shapeCreationTime - end + if(($originalOriginX == (($shapeDataPoints[0].to_f)/100)*$vbox_width) && ($originalOriginY == (($shapeDataPoints[1].to_f)/100)*$vbox_height)) + # do not update the rectangle count + else + $rectangle_count = $rectangle_count + 1 + end + $global_shape_count += 1 + $xml.g(:class => :shape, :id => "draw#{$global_shape_count}", :timestamp => $shapeCreationTime, :undo => $shapeUndoTime, :shape => "rect#{$rectangle_count}", :style => "stroke:\##{$colour_hex}; stroke-width:#{$shapeThickness}; visibility:hidden; fill:none") do + $originX = (($shapeDataPoints[0].to_f)/100)*$vbox_width + $originY = (($shapeDataPoints[1].to_f)/100)*$vbox_height + $originalOriginX = $originX + $originalOriginY = $originY + rectWidth = (($shapeDataPoints[2].to_f - $shapeDataPoints[0].to_f)/100)*$vbox_width + rectHeight = (($shapeDataPoints[3].to_f - $shapeDataPoints[1].to_f)/100)*$vbox_height + + # Cannot have a negative height or width so we adjust + if(rectHeight < 0) + $originY = $originY + rectHeight + rectHeight = rectHeight.abs + end + if(rectWidth < 0) + $originX = $originX + rectWidth + rectWidth = rectWidth.abs + end + if $is_square == "true" + #width of the square as reference + $xml.rect(:x => $originX, :y => $originY, :width => rectWidth, :height => rectWidth) + else + $xml.rect(:x => $originX, :y => $originY, :width => rectWidth, :height => rectHeight) + end + $prev_time = $shapeCreationTime + end end def storeTriangleShape - if(($originalOriginX == (($shapeDataPoints[0].to_f)/100)*$vbox_width) && ($originalOriginY == (($shapeDataPoints[1].to_f)/100)*$vbox_height)) - # do not update the triangle count - else - $triangle_count = $triangle_count + 1 - end - $global_shape_count += 1 - $xml.g(:class => :shape, :id => "draw#{$global_shape_count}", :timestamp => $shapeCreationTime, :undo => $shapeUndoTime, :shape => "triangle#{$triangle_count}", :style => "stroke:\##{$colour_hex}; stroke-width:#{$shapeThickness}; visibility:hidden; fill:none") do + if(($originalOriginX == (($shapeDataPoints[0].to_f)/100)*$vbox_width) && ($originalOriginY == (($shapeDataPoints[1].to_f)/100)*$vbox_height)) + # do not update the triangle count + else + $triangle_count = $triangle_count + 1 + end + $global_shape_count += 1 + $xml.g(:class => :shape, :id => "draw#{$global_shape_count}", :timestamp => $shapeCreationTime, :undo => $shapeUndoTime, :shape => "triangle#{$triangle_count}", :style => "stroke:\##{$colour_hex}; stroke-width:#{$shapeThickness}; visibility:hidden; fill:none") do - $originX = (($shapeDataPoints[0].to_f)/100)*$vbox_width - $originY = (($shapeDataPoints[1].to_f)/100)*$vbox_height + $originX = (($shapeDataPoints[0].to_f)/100)*$vbox_width + $originY = (($shapeDataPoints[1].to_f)/100)*$vbox_height - #3 points (p0, p1 and p2) to draw a triangle + #3 points (p0, p1 and p2) to draw a triangle - base = (($shapeDataPoints[2].to_f - $shapeDataPoints[0].to_f)/100)*$vbox_width + base = (($shapeDataPoints[2].to_f - $shapeDataPoints[0].to_f)/100)*$vbox_width - x0 = $originX + (base.to_f / 2.0) - x1 = $originX - x2 = $originX + base.to_f + x0 = $originX + (base.to_f / 2.0) + x1 = $originX + x2 = $originX + base.to_f - height = (($shapeDataPoints[3].to_f - $shapeDataPoints[1].to_f)/100)*$vbox_height + height = (($shapeDataPoints[3].to_f - $shapeDataPoints[1].to_f)/100)*$vbox_height - y0 = $originY - y1 = $originY + height - y2 = y1 + y0 = $originY + y1 = $originY + height + y2 = y1 - p0 = "#{x0},#{y0}" - p1 = "#{x1},#{y1}" - p2 = "#{x2},#{y2}" + p0 = "#{x0},#{y0}" + p1 = "#{x1},#{y1}" + p2 = "#{x2},#{y2}" - $originalOriginX = $originX - $originalOriginY = $originY + $originalOriginX = $originX + $originalOriginY = $originY - $xml.polyline(:points => "#{p0} #{p1} #{p2} #{p0}") - $prev_time = $shapeCreationTime - end + $xml.polyline(:points => "#{p0} #{p1} #{p2} #{p0}") + $prev_time = $shapeCreationTime + end end def storeEllipseShape - if(($originalOriginX == (($shapeDataPoints[0].to_f)/100)*$vbox_width) && ($originalOriginY == (($shapeDataPoints[1].to_f)/100)*$vbox_height)) - # do not update the rectangle count - else - $ellipse_count = $ellipse_count + 1 - end # end (($originalOriginX == (($shapeDataPoints[0].to_f)/100)*$vbox_width) && ($originalOriginY == (($shapeDataPoints[1].to_f)/100)*$vbox_height)) - $global_shape_count += 1 - $xml.g(:class => :shape, :id => "draw#{$global_shape_count}", :timestamp => $shapeCreationTime, :undo => $shapeUndoTime, :shape => "ellipse#{$ellipse_count}", :style =>"stroke:\##{$colour_hex}; stroke-width:#{$shapeThickness}; visibility:hidden; fill:none") do - $originX = (($shapeDataPoints[0].to_f)/100)*$vbox_width - $originY = (($shapeDataPoints[1].to_f)/100)*$vbox_height - $originalOriginX = $originX - $originalOriginY = $originY - ellipseWidth = (($shapeDataPoints[2].to_f - $shapeDataPoints[0].to_f)/100)*$vbox_width - ellipseHeight = (($shapeDataPoints[3].to_f - $shapeDataPoints[1].to_f)/100)*$vbox_height - if(ellipseHeight < 0) - $originY = $originY + ellipseHeight - ellipseHeight = ellipseHeight.abs - end - if(ellipseWidth < 0) - $originX = $originX + ellipseWidth - ellipseWidth = ellipseWidth.abs - end - if $is_circle == "true" - #Use width as reference - $xml.circle(:cx => $originX+(ellipseWidth/2), :cy => $originY+(ellipseWidth/2), :r => ellipseWidth/2) - else - $xml.ellipse(:cx => $originX+(ellipseWidth/2), :cy => $originY+(ellipseHeight/2), :rx => ellipseWidth/2, :ry => ellipseHeight/2) - end - $prev_time = $shapeCreationTime - end # end xml.g + if(($originalOriginX == (($shapeDataPoints[0].to_f)/100)*$vbox_width) && ($originalOriginY == (($shapeDataPoints[1].to_f)/100)*$vbox_height)) + # do not update the rectangle count + else + $ellipse_count = $ellipse_count + 1 + end # end (($originalOriginX == (($shapeDataPoints[0].to_f)/100)*$vbox_width) && ($originalOriginY == (($shapeDataPoints[1].to_f)/100)*$vbox_height)) + $global_shape_count += 1 + $xml.g(:class => :shape, :id => "draw#{$global_shape_count}", :timestamp => $shapeCreationTime, :undo => $shapeUndoTime, :shape => "ellipse#{$ellipse_count}", :style =>"stroke:\##{$colour_hex}; stroke-width:#{$shapeThickness}; visibility:hidden; fill:none") do + $originX = (($shapeDataPoints[0].to_f)/100)*$vbox_width + $originY = (($shapeDataPoints[1].to_f)/100)*$vbox_height + $originalOriginX = $originX + $originalOriginY = $originY + ellipseWidth = (($shapeDataPoints[2].to_f - $shapeDataPoints[0].to_f)/100)*$vbox_width + ellipseHeight = (($shapeDataPoints[3].to_f - $shapeDataPoints[1].to_f)/100)*$vbox_height + if(ellipseHeight < 0) + $originY = $originY + ellipseHeight + ellipseHeight = ellipseHeight.abs + end + if(ellipseWidth < 0) + $originX = $originX + ellipseWidth + ellipseWidth = ellipseWidth.abs + end + if $is_circle == "true" + #Use width as reference + $xml.circle(:cx => $originX+(ellipseWidth/2), :cy => $originY+(ellipseWidth/2), :r => ellipseWidth/2) + else + $xml.ellipse(:cx => $originX+(ellipseWidth/2), :cy => $originY+(ellipseHeight/2), :rx => ellipseWidth/2, :ry => ellipseHeight/2) + end + $prev_time = $shapeCreationTime + end # end xml.g end def storeTextShape - $originX = (($shapeDataPoints[0].to_f)/100)*$vbox_width - $originY = (($shapeDataPoints[1].to_f)/100)*$vbox_height - if(($originalOriginX == $originX) && ($originalOriginY == $originY)) - # do not update the text count - else - $text_count = $text_count + 1 - end - font_size_factor = 1.7 - width_extra_percent = -0.7 - height_extra_percent = 1 - width = ( ($textBoxWidth.to_f + width_extra_percent) / 100.0) * $vbox_width - height = ( ($textBoxHeight.to_f + height_extra_percent ) / 100.0) * $vbox_height - y_gap = -30.0 - x_gap = 5.0 - $textFontSize_pixels = $textFontSize.to_f * font_size_factor - $global_shape_count += 1 - $xml.g(:class => :shape, :id => "draw#{$global_shape_count}", :timestamp => $shapeCreationTime, :undo => $shapeUndoTime, :shape => "text#{$text_count}", :style => "word-wrap: break-word; visibility:hidden; font-family: #{$textFontType}; font-size: #{$textFontSize_pixels}px;") do - $xml.switch do - $xml.foreignObject( :color => "##{$colour_hex}", :width => width, :height => height, :x => "#{((($shapeDataPoints[0].to_f)/100)*$vbox_width) + x_gap}", :y => "#{((($shapeDataPoints[1].to_f)/100) *$vbox_height ) + y_gap.to_f }") do - $xml.p( :xmlns => "http://www.w3.org/1999/xhtml" ) do - $xml.text($textValue) - end - end - end - $prev_time = $shapeCreationTime - end # end xml.g - $originalOriginX = $originX - $originalOriginY = $originY + $originX = (($shapeDataPoints[0].to_f)/100)*$vbox_width + $originY = (($shapeDataPoints[1].to_f)/100)*$vbox_height + if(($originalOriginX == $originX) && ($originalOriginY == $originY)) + # do not update the text count + else + $text_count = $text_count + 1 + end + font_size_factor = 1.7 + width_extra_percent = -0.7 + height_extra_percent = 1 + width = ( ($textBoxWidth.to_f + width_extra_percent) / 100.0) * $vbox_width + height = ( ($textBoxHeight.to_f + height_extra_percent ) / 100.0) * $vbox_height + y_gap = -30.0 + x_gap = 5.0 + $textFontSize_pixels = $textFontSize.to_f * font_size_factor + $global_shape_count += 1 + $xml.g(:class => :shape, :id => "draw#{$global_shape_count}", :timestamp => $shapeCreationTime, :undo => $shapeUndoTime, :shape => "text#{$text_count}", :style => "word-wrap: break-word; visibility:hidden; font-family: #{$textFontType}; font-size: #{$textFontSize_pixels}px;") do + $xml.switch do + $xml.foreignObject( :color => "##{$colour_hex}", :width => width, :height => height, :x => "#{((($shapeDataPoints[0].to_f)/100)*$vbox_width) + x_gap}", :y => "#{((($shapeDataPoints[1].to_f)/100) *$vbox_height ) + y_gap.to_f }") do + $xml.p( :xmlns => "http://www.w3.org/1999/xhtml" ) do + $xml.text($textValue) + end + end + end + $prev_time = $shapeCreationTime + end # end xml.g + $originalOriginX = $originX + $originalOriginY = $originY end def storePollResultShape(xml, shape) @@ -522,212 +522,212 @@ end # to translate the timestamps later based on these offsets # def calculateRecordEventsOffset - accumulated_duration = 0 - previous_stop_recording = $meeting_start.to_f - $rec_events.each do |event| - event[:offset] = event[:start_timestamp] - accumulated_duration - event[:duration] = event[:stop_timestamp] - event[:start_timestamp] - event[:accumulated_duration] = accumulated_duration - - previous_stop_recording = event[:stop_timestamp] - accumulated_duration += event[:duration] - end + accumulated_duration = 0 + previous_stop_recording = $meeting_start.to_f + $rec_events.each do |event| + event[:offset] = event[:start_timestamp] - accumulated_duration + event[:duration] = event[:stop_timestamp] - event[:start_timestamp] + event[:accumulated_duration] = accumulated_duration + + previous_stop_recording = event[:stop_timestamp] + accumulated_duration += event[:duration] + end end # -# Translated an arbitrary Unix timestamp to the recording timestamp. This is the +# Translated an arbitrary Unix timestamp to the recording timestamp. This is the # function that others will call # def translateTimestamp(timestamp) - new_timestamp = translateTimestamp_helper(timestamp.to_f).to_f + new_timestamp = translateTimestamp_helper(timestamp.to_f).to_f # BigBlueButton.logger.info("Translating #{timestamp}, old value=#{timestamp.to_f-$meeting_start.to_f}, new value=#{new_timestamp}") - new_timestamp + new_timestamp end # # Translated an arbitrary Unix timestamp to the recording timestamp # def translateTimestamp_helper(timestamp) - $rec_events.each do |event| - # if the timestamp comes before the start recording event, then the timestamp is translated to the moment it starts recording - if timestamp <= event[:start_timestamp] - return event[:start_timestamp] - event[:offset] - # if the timestamp is during the recording period, it is just translated to the new one using the offset - elsif timestamp > event[:start_timestamp] and timestamp <= event[:stop_timestamp] - return timestamp - event[:offset] - end - end - # if the timestamp comes after the last stop recording event, then the timestamp is translated to the last stop recording event timestamp - return timestamp - $rec_events.last()[:offset] + $rec_events.last()[:duration] + $rec_events.each do |event| + # if the timestamp comes before the start recording event, then the timestamp is translated to the moment it starts recording + if timestamp <= event[:start_timestamp] + return event[:start_timestamp] - event[:offset] + # if the timestamp is during the recording period, it is just translated to the new one using the offset + elsif timestamp > event[:start_timestamp] and timestamp <= event[:stop_timestamp] + return timestamp - event[:offset] + end + end + # if the timestamp comes after the last stop recording event, then the timestamp is translated to the last stop recording event timestamp + return timestamp - $rec_events.last()[:offset] + $rec_events.last()[:duration] end # # Given an event timestamp, says whether it occurs during a recording period or not. # def occursDuringRecording(timestamp) - $rec_events.each do |event| - if timestamp >= event[:start_timestamp] and timestamp <= event[:stop_timestamp] - return true - end - end - return false + $rec_events.each do |event| + if timestamp >= event[:start_timestamp] and timestamp <= event[:stop_timestamp] + return true + end + end + return false end # # Calculates the length of a recording # def computeRecordingLength() - recordingLength = 0 - $rec_events.each do |event| - recordingLength += event[:stop_timestamp] - event[:start_timestamp] - end - recordingLength + recordingLength = 0 + $rec_events.each do |event| + recordingLength += event[:stop_timestamp] - event[:start_timestamp] + end + recordingLength end def preprocessSlideEvents - new_slides_events = [] - $slides_events.each do |slide_event| - new_slide_event = slide_event.clone - $rec_events.each do |rec_event| - if new_slide_event[:timestamp] <= rec_event[:start_timestamp] - new_slide_event[:timestamp] = rec_event[:start_timestamp] - if not new_slides_events.empty? and new_slides_events.last()[:timestamp] == rec_event[:start_timestamp] - new_slides_events.pop() - end - new_slides_events << new_slide_event - break - elsif new_slide_event[:timestamp] > rec_event[:start_timestamp] and new_slide_event[:timestamp] <= rec_event[:stop_timestamp] - new_slides_events << new_slide_event - end - end - end - return new_slides_events + new_slides_events = [] + $slides_events.each do |slide_event| + new_slide_event = slide_event.clone + $rec_events.each do |rec_event| + if new_slide_event[:timestamp] <= rec_event[:start_timestamp] + new_slide_event[:timestamp] = rec_event[:start_timestamp] + if not new_slides_events.empty? and new_slides_events.last()[:timestamp] == rec_event[:start_timestamp] + new_slides_events.pop() + end + new_slides_events << new_slide_event + break + elsif new_slide_event[:timestamp] > rec_event[:start_timestamp] and new_slide_event[:timestamp] <= rec_event[:stop_timestamp] + new_slides_events << new_slide_event + end + end + end + return new_slides_events end def processSlideEvents - BigBlueButton.logger.info("Slide events processing") - # For each slide (there is only one image per slide) - $slides_events.each do |node| - # Ignore slide events that happened after the last recording period. - if(node[:timestamp].to_f > $rec_events.last[:stop_timestamp].to_f) - next - end - eventname = node['eventname'] - if eventname == "SharePresentationEvent" - $presentation_name = node.xpath(".//presentationName")[0].text() - else - slide_timestamp = node[:timestamp] - slide_start = ( translateTimestamp(slide_timestamp) / 1000 ).round(1) - orig_slide_start = ( slide_timestamp.to_f / 1000 ).round(1) - slide_number = node.xpath(".//slide")[0].text().to_i + BigBlueButton.logger.info("Slide events processing") + # For each slide (there is only one image per slide) + $slides_events.each do |node| + # Ignore slide events that happened after the last recording period. + if(node[:timestamp].to_f > $rec_events.last[:stop_timestamp].to_f) + next + end + eventname = node['eventname'] + if eventname == "SharePresentationEvent" + $presentation_name = node.xpath(".//presentationName")[0].text() + else + slide_timestamp = node[:timestamp] + slide_start = ( translateTimestamp(slide_timestamp) / 1000 ).round(1) + orig_slide_start = ( slide_timestamp.to_f / 1000 ).round(1) + slide_number = node.xpath(".//slide")[0].text().to_i slide_number = slide_number < 0 ? 0 : slide_number - slide_src = "presentation/#{$presentation_name}/slide-#{slide_number + 1}.png" + slide_src = "presentation/#{$presentation_name}/slide-#{slide_number + 1}.png" txt_file_path = "presentation/#{$presentation_name}/textfiles/slide-#{slide_number + 1}.txt" slide_text = File.exist?("#{$process_dir}/#{txt_file_path}") ? txt_file_path : nil - image_url = "#{$process_dir}/#{slide_src}" - - if !File.exist?(image_url) - BigBlueButton.logger.warn("Missing image file #{slide_src}!") - # Emergency last-ditch blank image creation - FileUtils.mkdir_p("#{$process_dir}/presentation/#{$presentation_name}") - command = "convert -size 1600x1200 xc:white -quality 90 +dither -depth 8 -colors 256 #{image_url}" - BigBlueButton.execute(command) - end - - slide_size = FastImage.size(image_url) - current_index = $slides_events.index(node) - if(current_index + 1 < $slides_events.length) - slide_end = ( translateTimestamp($slides_events[current_index + 1][:timestamp]) / 1000 ).round(1) - orig_slide_end = ( $slides_events[current_index + 1][:timestamp].to_f / 1000 ).round(1) - else - slide_end = ( translateTimestamp($meeting_end) / 1000 ).round(1) - orig_slide_end = ( $meeting_end.to_f / 1000 ).round(1) - end - - if slide_start == slide_end - BigBlueButton.logger.info("#{slide_src} is never displayed (slide_start = slide_end), so it won't be included in the svg") - next - end - - BigBlueButton.logger.info("Processing slide image") - # Is this a new image or one previously viewed? - if($slides_compiled[[slide_src, slide_size[1], slide_size[0]]] == nil) - # If it is, add it to the list with all the data. - $slides_compiled[[slide_src, slide_size[1], slide_size[0]]] = [[slide_start], [slide_end], $global_slide_count, slide_text, [orig_slide_start], [orig_slide_end]] - $global_slide_count = $global_slide_count + 1 - else - # If not, append new in and out times to the old entry - # But if the previous slide_end is equal to the current slide_start, we just pop the previous slide_end and push the current one - # It will avoid the duplication of the thumbnails on the playback - if($slides_compiled[[slide_src, slide_size[1], slide_size[0]]][1].last == slide_start) - $slides_compiled[[slide_src, slide_size[1], slide_size[0]]][1].pop - $slides_compiled[[slide_src, slide_size[1], slide_size[0]]][1] << slide_end - else - $slides_compiled[[slide_src, slide_size[1], slide_size[0]]][0] << slide_start - $slides_compiled[[slide_src, slide_size[1], slide_size[0]]][1] << slide_end - end - $slides_compiled[[slide_src, slide_size[1], slide_size[0]]][4] << orig_slide_start - $slides_compiled[[slide_src, slide_size[1], slide_size[0]]][5] << orig_slide_end - end - - $ss[(slide_start..slide_end)] = slide_size # store the size of the slide at that range of time - puts "#{slide_src} : #{slide_start} -> #{slide_end}" - end - end + image_url = "#{$process_dir}/#{slide_src}" + + if !File.exist?(image_url) + BigBlueButton.logger.warn("Missing image file #{slide_src}!") + # Emergency last-ditch blank image creation + FileUtils.mkdir_p("#{$process_dir}/presentation/#{$presentation_name}") + command = "convert -size 1600x1200 xc:white -quality 90 +dither -depth 8 -colors 256 #{image_url}" + BigBlueButton.execute(command) + end + + slide_size = FastImage.size(image_url) + current_index = $slides_events.index(node) + if(current_index + 1 < $slides_events.length) + slide_end = ( translateTimestamp($slides_events[current_index + 1][:timestamp]) / 1000 ).round(1) + orig_slide_end = ( $slides_events[current_index + 1][:timestamp].to_f / 1000 ).round(1) + else + slide_end = ( translateTimestamp($meeting_end) / 1000 ).round(1) + orig_slide_end = ( $meeting_end.to_f / 1000 ).round(1) + end + + if slide_start == slide_end + BigBlueButton.logger.info("#{slide_src} is never displayed (slide_start = slide_end), so it won't be included in the svg") + next + end + + BigBlueButton.logger.info("Processing slide image") + # Is this a new image or one previously viewed? + if($slides_compiled[[slide_src, slide_size[1], slide_size[0]]] == nil) + # If it is, add it to the list with all the data. + $slides_compiled[[slide_src, slide_size[1], slide_size[0]]] = [[slide_start], [slide_end], $global_slide_count, slide_text, [orig_slide_start], [orig_slide_end]] + $global_slide_count = $global_slide_count + 1 + else + # If not, append new in and out times to the old entry + # But if the previous slide_end is equal to the current slide_start, we just pop the previous slide_end and push the current one + # It will avoid the duplication of the thumbnails on the playback + if($slides_compiled[[slide_src, slide_size[1], slide_size[0]]][1].last == slide_start) + $slides_compiled[[slide_src, slide_size[1], slide_size[0]]][1].pop + $slides_compiled[[slide_src, slide_size[1], slide_size[0]]][1] << slide_end + else + $slides_compiled[[slide_src, slide_size[1], slide_size[0]]][0] << slide_start + $slides_compiled[[slide_src, slide_size[1], slide_size[0]]][1] << slide_end + end + $slides_compiled[[slide_src, slide_size[1], slide_size[0]]][4] << orig_slide_start + $slides_compiled[[slide_src, slide_size[1], slide_size[0]]][5] << orig_slide_end + end + + $ss[(slide_start..slide_end)] = slide_size # store the size of the slide at that range of time + puts "#{slide_src} : #{slide_start} -> #{slide_end}" + end + end end def processShapesAndClears - # Create shapes.svg file from the events.xml - BigBlueButton.logger.info("Creating shapes.svg") - $shapes_svg = Nokogiri::XML::Builder.new do |xml| - $xml = xml - - processClearEvents() - processUndoEvents() - - # Put in the last clear events numbers (previous clear to the end of the slideshow) - #endPresentationTime = ( $end_time.to_f / 1000 ).round(1) - endPresentationTime = $end_time.to_f - $clearPageTimes[($prev_clear_time..endPresentationTime)] = [$pageCleared, $canvas_number, nil, nil] - - # Put the headers on the svg xml file. - $xml.doc.create_internal_subset('svg', "-//W3C//DTD SVG 1.1//EN", "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd") - $xml.svg(:id => :svgfile, :style => 'position:absolute; height:600px; width:800px;', :xmlns => 'http://www.w3.org/2000/svg', 'xmlns:xlink' => 'http://www.w3.org/1999/xlink', :version => '1.1', :viewBox => :'0 0 800 600') do - - # This is for the first image. It is a placeholder for an image that doesn't exist. - $xml.image(:id => :image0, :class => 'slide', :in => 0, :out => $first_slide_start, :src => "logo.png", :width => 800) - $xml.g(:class => :canvas, :id => :canvas0, :image => :image0, :display => :none) - $presentation_name = "" - - processSlideEvents() - processClearImages() - - BigBlueButton.logger.info("Printing out the gathered images") - # Print out the gathered/detected images. - $slides_compiled.each do |key, val| - $val = val - $xml.image(:id => "image#{$val[2].to_i}", :class => 'slide', :in => $val[0].join(' '), :out => $val[1].join(' '), 'xlink:href' => key[0], :height => key[1], :width => key[2], :visibility => :hidden, :text => $val[3], :x => 0) - $canvas_number+=1 - $xml.g(:class => :canvas, :id => "canvas#{$val[2].to_i}", :image => "image#{$val[2].to_i}", :display => :none) do - - BigBlueButton.logger.info("Processing shapes within the image #{$val[2].to_i}") - # Select and print the shapes within the current image - $shape_events.each do |shape| - $shapeTimestamp = shape[:timestamp].to_f - $shapeCreationTime = ( translateTimestamp($shapeTimestamp) / 1000 ).round(1) - orig_shapeCreationTime = ( $shapeTimestamp.to_f / 1000 ).round(1) - in_this_image = false - index = 0 - numOfTimes = $val[0].length - - # Check if the current shape is to be drawn in this particular image - while((in_this_image == false) && (index < numOfTimes)) do - if((($val[4][index].to_f)..($val[5][index].to_f)) === orig_shapeCreationTime) # is the shape within the certain time of the image - in_this_image = true - end - index+=1 - end - - if(in_this_image) + # Create shapes.svg file from the events.xml + BigBlueButton.logger.info("Creating shapes.svg") + $shapes_svg = Nokogiri::XML::Builder.new do |xml| + $xml = xml + + processClearEvents() + processUndoEvents() + + # Put in the last clear events numbers (previous clear to the end of the slideshow) + #endPresentationTime = ( $end_time.to_f / 1000 ).round(1) + endPresentationTime = $end_time.to_f + $clearPageTimes[($prev_clear_time..endPresentationTime)] = [$pageCleared, $canvas_number, nil, nil] + + # Put the headers on the svg xml file. + $xml.doc.create_internal_subset('svg', "-//W3C//DTD SVG 1.1//EN", "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd") + $xml.svg(:id => :svgfile, :style => 'position:absolute; height:600px; width:800px;', :xmlns => 'http://www.w3.org/2000/svg', 'xmlns:xlink' => 'http://www.w3.org/1999/xlink', :version => '1.1', :viewBox => :'0 0 800 600') do + + # This is for the first image. It is a placeholder for an image that doesn't exist. + $xml.image(:id => :image0, :class => 'slide', :in => 0, :out => $first_slide_start, :src => "logo.png", :width => 800) + $xml.g(:class => :canvas, :id => :canvas0, :image => :image0, :display => :none) + $presentation_name = "" + + processSlideEvents() + processClearImages() + + BigBlueButton.logger.info("Printing out the gathered images") + # Print out the gathered/detected images. + $slides_compiled.each do |key, val| + $val = val + $xml.image(:id => "image#{$val[2].to_i}", :class => 'slide', :in => $val[0].join(' '), :out => $val[1].join(' '), 'xlink:href' => key[0], :height => key[1], :width => key[2], :visibility => :hidden, :text => $val[3], :x => 0) + $canvas_number+=1 + $xml.g(:class => :canvas, :id => "canvas#{$val[2].to_i}", :image => "image#{$val[2].to_i}", :display => :none) do + + BigBlueButton.logger.info("Processing shapes within the image #{$val[2].to_i}") + # Select and print the shapes within the current image + $shape_events.each do |shape| + $shapeTimestamp = shape[:timestamp].to_f + $shapeCreationTime = ( translateTimestamp($shapeTimestamp) / 1000 ).round(1) + orig_shapeCreationTime = ( $shapeTimestamp.to_f / 1000 ).round(1) + in_this_image = false + index = 0 + numOfTimes = $val[0].length + + # Check if the current shape is to be drawn in this particular image + while((in_this_image == false) && (index < numOfTimes)) do + if((($val[4][index].to_f)..($val[5][index].to_f)) === orig_shapeCreationTime) # is the shape within the certain time of the image + in_this_image = true + end + index+=1 + end + + if(in_this_image) # Get variables BigBlueButton.logger.info shape.to_xml(:indent => 2) $shapeType = shape.xpath(".//type")[0].text() @@ -746,116 +746,116 @@ def processShapesAndClears when 'poll_result' # Just hand the 'shape' xml object to the poll rendering code. end - - # figure out undo time - BigBlueButton.logger.info("Figuring out undo time") - if($undos.has_key? ( shape[:timestamp] )) - $shapeUndoTime = ( translateTimestamp( $undos[ shape[:timestamp] ] ) / 1000).round(1) - else - $shapeUndoTime = -1 - end - - clear_time = -1 - $clearPageTimes.each do |clearTimeInstance, pageAndCanvasNumbers| - $clearTimeInstance = clearTimeInstance - $pageAndCanvasNumbers = pageAndCanvasNumbers - if(($clearTimeInstance.last > $shapeTimestamp) && ($pageAndCanvasNumbers[3] == "image#{$val[2].to_i}")) - if((clear_time > ( translateTimestamp($clearTimeInstance.last) / 1000 ).round(1)) || (clear_time == -1)) - clear_time = ( translateTimestamp($clearTimeInstance.last) / 1000 ).round(1) - end - end - end - - if($shapeUndoTime == -1) - if(clear_time == -1) - $shapeUndoTime = -1 # nothing changes - elsif(clear_time != -1) - $shapeUndoTime = clear_time - end - elsif($shapeUndoTime != -1) - if(clear_time == -1) - $shapeUndoTime = $shapeUndoTime #nothing changes - elsif (clear_time != -1) - if(clear_time < $shapeUndoTime) - $shapeUndoTime = clear_time - else - $shapeUndoTime = $shapeUndoTime # nothing changes - end - end - end - - # Process colours - $colour_hex = colour.to_i.to_s(16) # convert from base 10 to base 16 (hex) - $colour_hex='0'*(6-$colour_hex.length) + $colour_hex # pad the number with 0's to give it a length of 6 - - # resolve the current image height and width - $ss.each do |t,size| - if t === $shapeCreationTime - $vbox_width = size[0] - $vbox_height = size[1] - end - end - + + # figure out undo time + BigBlueButton.logger.info("Figuring out undo time") + if($undos.has_key? ( shape[:timestamp] )) + $shapeUndoTime = ( translateTimestamp( $undos[ shape[:timestamp] ] ) / 1000).round(1) + else + $shapeUndoTime = -1 + end + + clear_time = -1 + $clearPageTimes.each do |clearTimeInstance, pageAndCanvasNumbers| + $clearTimeInstance = clearTimeInstance + $pageAndCanvasNumbers = pageAndCanvasNumbers + if(($clearTimeInstance.last > $shapeTimestamp) && ($pageAndCanvasNumbers[3] == "image#{$val[2].to_i}")) + if((clear_time > ( translateTimestamp($clearTimeInstance.last) / 1000 ).round(1)) || (clear_time == -1)) + clear_time = ( translateTimestamp($clearTimeInstance.last) / 1000 ).round(1) + end + end + end + + if($shapeUndoTime == -1) + if(clear_time == -1) + $shapeUndoTime = -1 # nothing changes + elsif(clear_time != -1) + $shapeUndoTime = clear_time + end + elsif($shapeUndoTime != -1) + if(clear_time == -1) + $shapeUndoTime = $shapeUndoTime #nothing changes + elsif (clear_time != -1) + if(clear_time < $shapeUndoTime) + $shapeUndoTime = clear_time + else + $shapeUndoTime = $shapeUndoTime # nothing changes + end + end + end + + # Process colours + $colour_hex = colour.to_i.to_s(16) # convert from base 10 to base 16 (hex) + $colour_hex='0'*(6-$colour_hex.length) + $colour_hex # pad the number with 0's to give it a length of 6 + + # resolve the current image height and width + $ss.each do |t,size| + if t === $shapeCreationTime + $vbox_width = size[0] + $vbox_height = size[1] + end + end + case $shapeType when 'pencil' - storePencilShape() + storePencilShape() when 'line' - storeLineShape() + storeLineShape() when 'rectangle' - square = shape.xpath(".//square") - if square.length > 0 - $is_square = square[0].text() - else - $is_square = 'false' - end - storeRectShape() + square = shape.xpath(".//square") + if square.length > 0 + $is_square = square[0].text() + else + $is_square = 'false' + end + storeRectShape() when 'triangle' - storeTriangleShape() + storeTriangleShape() when 'ellipse' - circle = shape.xpath(".//circle") - if circle.length > 0 - $is_circle = circle[0].text() - else - $is_circle = 'false' - end - storeEllipseShape() + circle = shape.xpath(".//circle") + if circle.length > 0 + $is_circle = circle[0].text() + else + $is_circle = 'false' + end + storeEllipseShape() when 'text' - $textBoxWidth = shape.xpath(".//textBoxWidth")[0].text() - $textBoxHeight = shape.xpath(".//textBoxHeight")[0].text() - storeTextShape() + $textBoxWidth = shape.xpath(".//textBoxWidth")[0].text() + $textBoxHeight = shape.xpath(".//textBoxHeight")[0].text() + storeTextShape() when 'poll_result' storePollResultShape($xml, shape) - end - end # end if(in_this_image) - end # end shape_events.each do |shape| - end - end - end - end + end + end # end if(in_this_image) + end # end shape_events.each do |shape| + end + end + end + end end def processChatMessages - BigBlueButton.logger.info("Processing chat events") - # Create slides.xml and chat. - $slides_doc = Nokogiri::XML::Builder.new do |xml| - $xml = xml - $xml.popcorn { - # Process chat events. - current_time = 0 - $rec_events.each do |re| - $chat_events.each do |node| - if (node[:timestamp].to_i >= re[:start_timestamp] and node[:timestamp].to_i <= re[:stop_timestamp]) - chat_timestamp = node[:timestamp] - chat_sender = node.xpath(".//sender")[0].text() - chat_message = BigBlueButton::Events.linkify(node.xpath(".//message")[0].text()) - chat_start = ( translateTimestamp(chat_timestamp) / 1000).to_i - $xml.chattimeline(:in => chat_start, :direction => :down, :name => chat_sender, :message => chat_message, :target => :chat ) - end - end - current_time += re[:stop_timestamp] - re[:start_timestamp] - end - } - end + BigBlueButton.logger.info("Processing chat events") + # Create slides.xml and chat. + $slides_doc = Nokogiri::XML::Builder.new do |xml| + $xml = xml + $xml.popcorn { + # Process chat events. + current_time = 0 + $rec_events.each do |re| + $chat_events.each do |node| + if (node[:timestamp].to_i >= re[:start_timestamp] and node[:timestamp].to_i <= re[:stop_timestamp]) + chat_timestamp = node[:timestamp] + chat_sender = node.xpath(".//sender")[0].text() + chat_message = BigBlueButton::Events.linkify(node.xpath(".//message")[0].text()) + chat_start = ( translateTimestamp(chat_timestamp) / 1000).to_i + $xml.chattimeline(:in => chat_start, :direction => :down, :name => chat_sender, :message => chat_message, :target => :chat ) + end + end + current_time += re[:stop_timestamp] - re[:start_timestamp] + end + } + end end $vbox_width = 1600 @@ -912,175 +912,175 @@ begin if ($playback == "presentation") - # This script lives in scripts/archive/steps while properties.yaml lives in scripts/ - bbb_props = YAML::load(File.open('../../core/scripts/bigbluebutton.yml')) - simple_props = YAML::load(File.open('presentation.yml')) + # This script lives in scripts/archive/steps while properties.yaml lives in scripts/ + bbb_props = YAML::load(File.open('../../core/scripts/bigbluebutton.yml')) + simple_props = YAML::load(File.open('presentation.yml')) log_dir = bbb_props['log_dir'] - logger = Logger.new("#{log_dir}/presentation/publish-#{$meeting_id}.log", 'daily' ) - BigBlueButton.logger = logger + logger = Logger.new("#{log_dir}/presentation/publish-#{$meeting_id}.log", 'daily' ) + BigBlueButton.logger = logger - BigBlueButton.logger.info("Setting recording dir") - recording_dir = bbb_props['recording_dir'] - BigBlueButton.logger.info("Setting process dir") - $process_dir = "#{recording_dir}/process/presentation/#{$meeting_id}" - BigBlueButton.logger.info("setting publish dir") - publish_dir = simple_props['publish_dir'] - BigBlueButton.logger.info("setting playback url info") + BigBlueButton.logger.info("Setting recording dir") + recording_dir = bbb_props['recording_dir'] + BigBlueButton.logger.info("Setting process dir") + $process_dir = "#{recording_dir}/process/presentation/#{$meeting_id}" + BigBlueButton.logger.info("setting publish dir") + publish_dir = simple_props['publish_dir'] + BigBlueButton.logger.info("setting playback url info") playback_protocol = bbb_props['playback_protocol'] - playback_host = bbb_props['playback_host'] - BigBlueButton.logger.info("setting target dir") - target_dir = "#{recording_dir}/publish/presentation/#{$meeting_id}" - if not FileTest.directory?(target_dir) - BigBlueButton.logger.info("Making dir target_dir") - FileUtils.mkdir_p target_dir - - package_dir = "#{target_dir}/#{$meeting_id}" - BigBlueButton.logger.info("Making dir package_dir") - FileUtils.mkdir_p package_dir - - begin - - if File.exist?("#{$process_dir}/webcams.webm") - BigBlueButton.logger.info("Making video dir") - video_dir = "#{package_dir}/video" - FileUtils.mkdir_p video_dir - BigBlueButton.logger.info("Made video dir - copying: #{$process_dir}/webcams.webm to -> #{video_dir}") - FileUtils.cp("#{$process_dir}/webcams.webm", video_dir) - BigBlueButton.logger.info("Copied .webm file") - else - audio_dir = "#{package_dir}/audio" - BigBlueButton.logger.info("Making audio dir") - FileUtils.mkdir_p audio_dir - BigBlueButton.logger.info("Made audio dir - copying: #{$process_dir}/audio.webm to -> #{audio_dir}") - FileUtils.cp("#{$process_dir}/audio.webm", audio_dir) - BigBlueButton.logger.info("Copied audio.webm file - copying: #{$process_dir}/audio.ogg to -> #{audio_dir}") - FileUtils.cp("#{$process_dir}/audio.ogg", audio_dir) - BigBlueButton.logger.info("Copied audio.ogg file") - end - - - processing_time = File.read("#{$process_dir}/processing_time") - - # Retrieve record events and calculate total recording duration. - $rec_events = BigBlueButton::Events.match_start_and_stop_rec_events( - BigBlueButton::Events.get_start_and_stop_rec_events("#{$process_dir}/events.xml")) - - recording_time = computeRecordingLength() - - # presentation_url = "/slides/" + $meeting_id + "/presentation" - @doc = Nokogiri::XML(File.open("#{$process_dir}/events.xml")) - - $meeting_start = @doc.xpath("//event")[0][:timestamp] - $meeting_end = @doc.xpath("//event").last()[:timestamp] - - $version = BigBlueButton::Events.bbb_version("#{$process_dir}/events.xml") - $version_atleast_0_9_0 = BigBlueButton::Events.bbb_version_compare("#{$process_dir}/events.xml", 0, 9, 0) - BigBlueButton.logger.info("Creating metadata.xml") + playback_host = bbb_props['playback_host'] + BigBlueButton.logger.info("setting target dir") + target_dir = "#{recording_dir}/publish/presentation/#{$meeting_id}" + if not FileTest.directory?(target_dir) + BigBlueButton.logger.info("Making dir target_dir") + FileUtils.mkdir_p target_dir + + package_dir = "#{target_dir}/#{$meeting_id}" + BigBlueButton.logger.info("Making dir package_dir") + FileUtils.mkdir_p package_dir + + begin + + if File.exist?("#{$process_dir}/webcams.webm") + BigBlueButton.logger.info("Making video dir") + video_dir = "#{package_dir}/video" + FileUtils.mkdir_p video_dir + BigBlueButton.logger.info("Made video dir - copying: #{$process_dir}/webcams.webm to -> #{video_dir}") + FileUtils.cp("#{$process_dir}/webcams.webm", video_dir) + BigBlueButton.logger.info("Copied .webm file") + else + audio_dir = "#{package_dir}/audio" + BigBlueButton.logger.info("Making audio dir") + FileUtils.mkdir_p audio_dir + BigBlueButton.logger.info("Made audio dir - copying: #{$process_dir}/audio.webm to -> #{audio_dir}") + FileUtils.cp("#{$process_dir}/audio.webm", audio_dir) + BigBlueButton.logger.info("Copied audio.webm file - copying: #{$process_dir}/audio.ogg to -> #{audio_dir}") + FileUtils.cp("#{$process_dir}/audio.ogg", audio_dir) + BigBlueButton.logger.info("Copied audio.ogg file") + end + + + processing_time = File.read("#{$process_dir}/processing_time") + + # Retrieve record events and calculate total recording duration. + $rec_events = BigBlueButton::Events.match_start_and_stop_rec_events( + BigBlueButton::Events.get_start_and_stop_rec_events("#{$process_dir}/events.xml")) + + recording_time = computeRecordingLength() + + # presentation_url = "/slides/" + $meeting_id + "/presentation" + @doc = Nokogiri::XML(File.open("#{$process_dir}/events.xml")) + + $meeting_start = @doc.xpath("//event")[0][:timestamp] + $meeting_end = @doc.xpath("//event").last()[:timestamp] + + $version = BigBlueButton::Events.bbb_version("#{$process_dir}/events.xml") + $version_atleast_0_9_0 = BigBlueButton::Events.bbb_version_compare("#{$process_dir}/events.xml", 0, 9, 0) + BigBlueButton.logger.info("Creating metadata.xml") # Get the real-time start and end timestamp match = /.*-(\d+)$/.match($meeting_id) real_start_time = match[1] real_end_time = (real_start_time.to_i + ($meeting_end.to_i - $meeting_start.to_i)).to_s - # Create metadata.xml - b = Builder::XmlMarkup.new(:indent => 2) - - metaxml = b.recording { - b.id($meeting_id) - b.state("available") - b.published(true) - # Date Format for recordings: Thu Mar 04 14:05:56 UTC 2010 - b.start_time(real_start_time) - b.end_time(real_end_time) - b.playback { - b.format("presentation") - b.link("#{playback_protocol}://#{playback_host}/playback/presentation/0.9.0/playback.html?meetingId=#{$meeting_id}") - b.processing_time("#{processing_time}") - b.duration("#{recording_time}") - } - b.meta { - BigBlueButton::Events.get_meeting_metadata("#{$process_dir}/events.xml").each { |k,v| b.method_missing(k,v) } - } - } - metadata_xml = File.new("#{package_dir}/metadata.xml","w") - metadata_xml.write(metaxml) - metadata_xml.close - BigBlueButton.logger.info("Generating xml for slides and chat") - - #Create slides.xml - - # Gathering all the events from the events.xml - $slides_events = @doc.xpath("//event[@eventname='GotoSlideEvent' or @eventname='SharePresentationEvent']") - $chat_events = @doc.xpath("//event[@eventname='PublicChatEvent']") - $shape_events = @doc.xpath("//event[@eventname='AddShapeEvent' or @eventname='ModifyTextEvent']") # for the creation of shapes - $panzoom_events = @doc.xpath("//event[@eventname='ResizeAndMoveSlideEvent']") # for the action of panning and/or zooming - $cursor_events = @doc.xpath("//event[@eventname='CursorMoveEvent']") - $clear_page_events = @doc.xpath("//event[@eventname='ClearPageEvent']") # for clearing the svg image - $undo_events = @doc.xpath("//event[@eventname='UndoShapeEvent']") # for undoing shapes. - $join_time = $meeting_start.to_f - $end_time = $meeting_end.to_f - - calculateRecordEventsOffset() - - first_presentation_start_node = @doc.xpath("//event[@eventname='SharePresentationEvent']") - first_presentation_start = $meeting_end - if not first_presentation_start_node.empty? - first_presentation_start = first_presentation_start_node[0][:timestamp] - end - $first_slide_start = ( translateTimestamp(first_presentation_start) / 1000 ).round(1) - - processChatMessages() - - processShapesAndClears() - - processPanAndZooms() - - processCursorEvents() - - # Write slides.xml to file - File.open("#{package_dir}/slides_new.xml", 'w') { |f| f.puts $slides_doc.to_xml } - # Write shapes.svg to file - File.open("#{package_dir}/#{$shapes_svg_filename}", 'w') { |f| f.puts $shapes_svg.to_xml.gsub(%r"\s*\<g.*/\>", "") } #.gsub(%r"\s*\<g.*\>\s*\</g\>", "") } - - # Write panzooms.xml to file - File.open("#{package_dir}/#{$panzooms_xml_filename}", 'w') { |f| f.puts $panzooms_xml.to_xml } - - # Write panzooms.xml to file - File.open("#{package_dir}/#{$cursor_xml_filename}", 'w') { |f| f.puts $cursor_xml.to_xml } - - BigBlueButton.logger.info("Copying files to package dir") - FileUtils.cp_r("#{$process_dir}/presentation", package_dir) - BigBlueButton.logger.info("Copied files to package dir") - - BigBlueButton.logger.info("Publishing slides") - # Now publish this recording files by copying them into the publish folder. - if not FileTest.directory?(publish_dir) - FileUtils.mkdir_p publish_dir - end - FileUtils.cp_r(package_dir, publish_dir) # Copy all the files. - BigBlueButton.logger.info("Finished publishing script presentation.rb successfully.") + # Create metadata.xml + b = Builder::XmlMarkup.new(:indent => 2) + + metaxml = b.recording { + b.id($meeting_id) + b.state("available") + b.published(true) + # Date Format for recordings: Thu Mar 04 14:05:56 UTC 2010 + b.start_time(real_start_time) + b.end_time(real_end_time) + b.playback { + b.format("presentation") + b.link("#{playback_protocol}://#{playback_host}/playback/presentation/0.9.0/playback.html?meetingId=#{$meeting_id}") + b.processing_time("#{processing_time}") + b.duration("#{recording_time}") + } + b.meta { + BigBlueButton::Events.get_meeting_metadata("#{$process_dir}/events.xml").each { |k,v| b.method_missing(k,v) } + } + } + metadata_xml = File.new("#{package_dir}/metadata.xml","w") + metadata_xml.write(metaxml) + metadata_xml.close + BigBlueButton.logger.info("Generating xml for slides and chat") + + #Create slides.xml + + # Gathering all the events from the events.xml + $slides_events = @doc.xpath("//event[@eventname='GotoSlideEvent' or @eventname='SharePresentationEvent']") + $chat_events = @doc.xpath("//event[@eventname='PublicChatEvent']") + $shape_events = @doc.xpath("//event[@eventname='AddShapeEvent' or @eventname='ModifyTextEvent']") # for the creation of shapes + $panzoom_events = @doc.xpath("//event[@eventname='ResizeAndMoveSlideEvent']") # for the action of panning and/or zooming + $cursor_events = @doc.xpath("//event[@eventname='CursorMoveEvent']") + $clear_page_events = @doc.xpath("//event[@eventname='ClearPageEvent']") # for clearing the svg image + $undo_events = @doc.xpath("//event[@eventname='UndoShapeEvent']") # for undoing shapes. + $join_time = $meeting_start.to_f + $end_time = $meeting_end.to_f + + calculateRecordEventsOffset() + + first_presentation_start_node = @doc.xpath("//event[@eventname='SharePresentationEvent']") + first_presentation_start = $meeting_end + if not first_presentation_start_node.empty? + first_presentation_start = first_presentation_start_node[0][:timestamp] + end + $first_slide_start = ( translateTimestamp(first_presentation_start) / 1000 ).round(1) + + processChatMessages() + + processShapesAndClears() + + processPanAndZooms() + + processCursorEvents() + + # Write slides.xml to file + File.open("#{package_dir}/slides_new.xml", 'w') { |f| f.puts $slides_doc.to_xml } + # Write shapes.svg to file + File.open("#{package_dir}/#{$shapes_svg_filename}", 'w') { |f| f.puts $shapes_svg.to_xml.gsub(%r"\s*\<g.*/\>", "") } #.gsub(%r"\s*\<g.*\>\s*\</g\>", "") } + + # Write panzooms.xml to file + File.open("#{package_dir}/#{$panzooms_xml_filename}", 'w') { |f| f.puts $panzooms_xml.to_xml } + + # Write panzooms.xml to file + File.open("#{package_dir}/#{$cursor_xml_filename}", 'w') { |f| f.puts $cursor_xml.to_xml } + + BigBlueButton.logger.info("Copying files to package dir") + FileUtils.cp_r("#{$process_dir}/presentation", package_dir) + BigBlueButton.logger.info("Copied files to package dir") + + BigBlueButton.logger.info("Publishing slides") + # Now publish this recording files by copying them into the publish folder. + if not FileTest.directory?(publish_dir) + FileUtils.mkdir_p publish_dir + end + FileUtils.cp_r(package_dir, publish_dir) # Copy all the files. + BigBlueButton.logger.info("Finished publishing script presentation.rb successfully.") BigBlueButton.logger.info("Removing processed files.") - FileUtils.rm_r(Dir.glob("#{$process_dir}/*")) + FileUtils.rm_r(Dir.glob("#{$process_dir}/*")) - BigBlueButton.logger.info("Removing published files.") - FileUtils.rm_r(Dir.glob("#{target_dir}/*")) + BigBlueButton.logger.info("Removing published files.") + FileUtils.rm_r(Dir.glob("#{target_dir}/*")) rescue Exception => e BigBlueButton.logger.error(e.message) - e.backtrace.each do |traceline| - BigBlueButton.logger.error(traceline) - end - exit 1 - end + e.backtrace.each do |traceline| + BigBlueButton.logger.error(traceline) + end + exit 1 + end publish_done = File.new("#{recording_dir}/status/published/#{$meeting_id}-presentation.done", "w") publish_done.write("Published #{$meeting_id}") publish_done.close - else - BigBlueButton.logger.info("#{target_dir} is already there") - end + else + BigBlueButton.logger.info("#{target_dir} is already there") + end end