Capture loaded source of audio tag with ruby n rails

I have a problem and was wondering if anyone could help. I need to save the source file (the currently loaded source file) of an audio tag. Sounds simple, but here’s the catch the source gives a random sound file on every request.

The audio tag is created, source set and played with javascript.

ex:


function createAudio() {
    var audio = document.createElement('audio');

    audio.setAttribute('id', 'file_audio')
    audio.setAttribute('controls', 'controls');
    audio.setAttribute('autoplay', 'true');
    audio.setAttribute('hidden', 'true');
    audio.appendChild(createSource());
    return audio;
}

function createSource() {
    var source = document.createElement('source');
    var d = new Date();
    source.setAttribute('id', 'file_audio_source')
    source.setAttribute('src', 'file.wav?r=' + d.getTime());
    source.setAttribute('type', 'audio/wav');
    return source;
}
this.switchAudio = function() {
    var d = new Date();
    $svjq("#file_audio").find('audio').remove();
    $svjq("#file_audio").find('source').remove();
    $svjq("#file_audio").find('embed').remove();
    if (Modernizr.audio.wav) {
        document.getElementById("file_audio").appendChild(createAudio());
    } else {
        $svjq("#file_audio").append('<embed id="file_audio_embed" name="file_audio_embed" src="file.wav?r=' + d.getTime() + '" autostart="true" cache="false" type="audio/wav" hidden="true" loop="false" enablejavascript="true">');
    }

};
this.playAgain = function() {
    if (Modernizr.audio.wav) {
        document.getElementById('file_audio').play();
    } else {
        document.getElementById('file_audio_embed').play();
    }
};

I need be able to save the currently loaded file in the source. If you access the file url in the browser it returns a different file. With automated processes, such using Watir-WebDriver, Capybara (Capybara-Webkit), Mechanize It still returns a random file.


require 'capybara'
session = Capybara::Session.new(:selenium)
session.visit('url')
session.click_link 'play sound' #on every click u get a new sound
session.click_link 'play again'

#file_audio_source
e = session.find_by_id('file_audio_source')
e[:src]

#save the current open page and opens it
#session.save_and_open_page

#returns different file
session.visit(e[:src])

#returns different file
session.execute_script("window.open('"+e[:src]+"')")

require 'Mechanize'
agent = Mechanize.new{|agent| agent.ssl_version, agent.verify_mode = 'SSLv3', OpenSSL::SSL::VERIFY_NONE}

filedata = agent.get(e[:src]).content
aFile = File.new("/Users/me/Documents/test/test111.wav", 'wb')
#aFile.syswrite(filedata)

Could the file be embedded into the html or cached? And is there a way to get it and save it locally?

Other options include recording from the sound device, (or using the mic to record the sound played, this option is not the ideal solution at all)

Many thanks in advance for any assistance or suggestions shared :slight_smile:

I have been struggling with this for far too long =)
ajt

Hi ajt,

Could the file be embedded into the html or cached?

You can use data URI’s to embed a file in the src attribute rather than linking to it.
http://stackoverflow.com/questions/2270151/is-it-possible-to-use-data-uris-in-video-and-audio-tags

So it finally is solved =)
Two ways to solve it !

  1. Yes it has something to do with the session
    if you load the js that embedds the audio tag and not play it through the browser with js
    then the file you got by executing the js that embeds is the file that would have been loaded.
    >>>> the file needed <<<<
function createSource() {
    var source = document.createElement('source');
    var d = new Date();
    source.setAttribute('id', 'file_audio_source')
    source.setAttribute('src', 'file.wav?r=' + d.getTime());
    source.setAttribute('type', 'audio/wav');
    return source;
}

run the above in
page.execute_script(‘here’)

  1. It is stored in the cache
    So now you just needed to find the location of the cache folder,
    then load the page and go and get the file in the cache (by getting
    the latest/newest wav file in cache)
    test_getfile.rb
#def loadFile
	 	
	 	require 'capybara'
		session = Capybara::Session.new(:selenium)
		session.visit('url')
		sleep(5)
		session.click_link 'Play sound'	
		sleep(20)		
		
	#end

	def getlatestdir(newdirs)
		times = Array.new
		newdirs.each_with_index do |newdir,index|
			times[index] = File::mtime(newdir)
		end

		temp = times[0]
		count = 0
		times.each_with_index do |time,index|
			if temp < time
				temp = time
				count = index
			end
		end

		return newdirs[count]
	end

	def getCacheDir
		#how to get the path
		#in irb enter
		#require 'capybara'
		#session = Capybara::Session.new(:selenium)
		#session.visit('https://www.google.co.za')
		#--- then open a new tab and enter about:cache
		#copy the disk cache device cache directory ( from /var/... to .../T/ )
		path = '/var/folders/9x/51cvmc215xx6zy9vd_64sxwc0000gn/T/'
		dirs = Dir.glob(path +'*/')
		newdirs = Array.new
		dirs.each_with_index do |dir,index|
			if(dir.include? 'webdriver-profile')
				newdirs[newdirs.length] = dir
			end
		end

		the_cache_dir = getlatestdir(newdirs) + 'Cache'

		puts the_cache_dir
		return the_cache_dir
	end

	def saveFile
		rifffile = ''
		count = 0
		the_cache_dir = getCacheDir
		files = Dir.glob(the_cache_dir + '/*/*/*')
		files.each_with_index do |file,index|
			bytes = open(file, 'rb'){|io|io.read}
			str = bytes[0].to_s + bytes[1].to_s + bytes[2].to_s + bytes[3].to_s
			#rifffiles[rifffiles.length] = file
                        #finds the wav file by file signature
			if(str == 'RIFF')
				count = index
				rifffile = file
			end
			#puts str
			#puts file
			#puts File.size(file)		
		end

		puts rifffile

		#read file bytes
		bytes = File.open(rifffile, 'rb'){|io|io.read}
		#write file to your directory
		f = File.new('testing2.wav', 'wb')
		f.syswrite(bytes)
	end

	saveFile

a big thank you for everyones assistance in solving this issue
=)
ajt

Thank you, awesome answer.
Good to know this for the future =)
The solution was a little easier than first thought.
I have post the solution.