ruby on rails 2.1 upload music and read id3 tags before saving to amazon S3
Sorry it has been so long since my last post. I doubt anyone is reading this anyways. In this article i’m going to attempt to show you what you need to know in order to upload a file (music in this case) into your rails application and safely tuck it away on amazons simple storage solution. I realize this is a very specific application. However, it took me two days to get this working properly so I figured i’d share what I did in order to get this working. I’m assuming you are using rails 2.1 (but that may not be required) and have already created your application. if not you can create and application by issuing the typical rails application_nam command
If you are just planning to upload file to S3 and do not need to manipulate them else do anything to them before they end up on the server. Then I suggest you just use the plugin.
simply install
script/plugin install http://svn.techno-weenie.net/projects/plugins/attachment_fu/
after that just follow the instructions on http://clarkware.com/cgi/blosxom/2007/02/24 you should be up and running in no time with the help of this plugin
Lets assume you don’t want to use the plugin
But why would we not want to use the plugin:?
- Way more code than you need for the task at hand
- No simple way to manipulate the file or extract data from it before sending to S3
So now that we are going to perform this operation manually there are a few things you will need for this example. You will need to install the mp3info gem as root at command prompt.
gem install mp3info
gem install aws-s3
Say yes to any dependencies once those two gems successfully install you will have to restart your webserver and they will be ready to use in your application
I’m going to skip over a lot here because I don’t know how you want to configure your application however the steps are pretty simple create some scaffold. Make an upload form.
and then save the data. I’m only going to show you the model code. I believe everything is self explanatory from there. I will be happy to field any questions if anyone cares to ask. Enought chit chat show me the code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | require "ftools" require "aws/s3" require "mp3info" class Song < ActiveRecord::Base include AWS::S3 belongs_to :user has_one :song_metadata before_validation :set_all_meta_data after_save :write_file after_destroy :delete_file before_create :connect_to_amazon validates_inclusion_of :mime_type, :in =>%w( audio/mpeg audio/mpg ), :message =>"The file you uploaded is not an mp3" validates_inclusion_of :file_size, :in =>300.kilobytes..20.megabytes, :message=>"must be between 300k and 20mb" attr_accessor :id3tags def song=(file_data) @file_data = file_data end def write_file buckets = Service.buckets bucketexists=false buckets.each do |bucket| if bucket.name == AppConfig.ec2["bucket"] bucketexists=true end end if !bucketexists Bucket.create(AppConfig.ec2["bucket"]) end @file_data.rewind if !S3Object.exists? get_file_url, AppConfig.ec2["bucket"] createsong_meta S3Object.store(get_file_url, @file_data.read, AppConfig.ec2["bucket"],:access => :public_read) end end def createsong_meta m = SongMetadata.new self.song_metadata = m if id3tags.title m.title = id3tags.title else m.title = "No song name set" end if id3tags.artist m.artist = id3tags.artist else m.artist = "No artist name set" end if id3tags.album m.album = id3tags.album else m.album = "No album name set" end m.year = id3tags.year m.track_number= id3tags.tracknum m.save! end def get_song self.connect_to_amazon S3Object.value mp3_url, AppConfig.ec2["bucket"] end def delete_file self.connect_to_amazon S3Object.delete mp3_url, AppConfig.ec2["bucket"] end def set_all_meta_data if @file_data!="" && @file_data @file_data.rewind self.mime_type = @file_data.content_type if self.mime_type == "audio/mpg" || self.mime_type=="audio/mpeg" tmplocal = "#{RAILS_ROOT}/tmp/musicfiles" tmpname = "#{Time.now}-#{@file_data.original_filename}" File.makedirs(tmplocal) File.open("#{tmplocal}/#{tmpname}", "w") { |file| file.write(@file_data.read) } mymp3 = Mp3Info.open("#{tmplocal}/#{tmpname}") self.id3tags = mymp3.tag self.bitrate = mymp3.bitrate self.samplerate = mymp3.samplerate self.samplerate = mymp3.samplerate self.mpeg_version= mymp3.mpeg_version self.layer = mymp3.layer self.length = mymp3.length self.file_size = @file_data.size mymp3.close File.delete("#{tmplocal}/#{tmpname}") self.mp3_url = get_file_url end end end def get_file_url "#{user_id}/xrays/#{id}/song/#{@file_data.original_filename}" end def connect_to_amazon Base.establish_connection!(:access_key_id=> AppConfig.ec2["access_key"], :secret_access_key => AppConfig.ec2["secret_key"]) end end |
That is really the meat and potatoes. It is all hanging out in the model nicely tucked away. getting the data out of S3 is simple and is left as an exercise for the reader. Obviously you need to insert your own access_key and secret key. I’m not making any assumptions about the configuration of your application and thus this is entirely us to you the reader as well. Hope this helps someone..