Skip to content

Instantly share code, notes, and snippets.

@DavidJRobertson
Created December 8, 2012 15:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DavidJRobertson/4240787 to your computer and use it in GitHub Desktop.
Save DavidJRobertson/4240787 to your computer and use it in GitHub Desktop.
#! /usr/bin/env ruby
require 'yaml'
require 'pp'
require 'erubis'
require 'mp3info'
require 'aws/s3'
require 'digest'
def reload_config
$config = YAML.load_file("config.yml")
AWS::S3::Base.establish_connection!(
:access_key_id => $config['s3']['accesskey']['id'],
:secret_access_key => $config['s3']['accesskey']['secret']
)
AWS::S3::DEFAULT_HOST.replace $config['s3']['hostname']
$bucketname = $config['s3']['bucket']
end
reload_config
$itunes_image_url = "FILL IN URL"
class Episode
def self.new_from_meta(filename, meta)
return Episode.new(filename, meta['title'], Date.parse(meta['date']), meta['synopsis'], meta['subtitle'], meta['tags'])
end
def initialize(filename, title, date, synopsis, subtitle = nil, tags = [], compiledname = nil)
@filename = filename
@title = title
@date = date
@synopsis = synopsis
@subtitle = subtitle
@tags = tags
@compiledname = compiledname
end
attr_accessor :filename, :title, :date, :synopsis, :tags, :subtitle, :compiledname
def duration
return @duration unless @duration.nil?
length = 0
Mp3Info.open("content/#{@filename}") do |mp3|
length = mp3.length
end
length = length.to_i
seconds = length % 60
minutes = (length / 60).to_i
@duration = "#{minutes}:#{seconds}"
end
def size
File.size "content/#{filename}"
end
def keywords
@tags.join ', ' unless @tags.nil? or @tags.empty?
end
def file_path(leader=true)
return "#{leader ? "/" : ""}assets/mp3/#{@compiledname}" unless @compiledname.nil?
return false
end
def file_url
return "#{$config['urlbase']}#{file_path}" unless file_path.nil?
return false
end
def path(leader=true)
return "#{leader ? "/" : ""}episode/#{@compiledname[0..-5]}.html" unless @compiledname.nil?
return false
end
def url
return "#{$config['urlbase']}#{path}" unless path.nil?
return false
end
end
def link_to(name, url)
return %Q{<a href="#{url}">#{name}</a>}
end
def compile()
puts "Compiling..."
meta = YAML.load_file("content/metadata.yml")
episodes = Array.new
filesfound = Array.new
touchedfiles = Array.new
Dir.glob('content/*.mp3') do |file|
filename = file[8..-1]
unless meta[filename].nil?
# Episode metadata already stored
episodes << Episode.new_from_meta(filename, meta[filename])
filesfound << filename
else
# No episode metadata stored for this yet
puts "Warning: no metadata found for file #{filename}"
end
end
# Check for files in meta but not found
meta.each do |file|
next if filesfound.include? file[0]
puts "Warning: found metadata for file #{file[0]}, but file itself is missing. Will not be published."
end
# Generate compiledname for all episodes.
episodes.each do |episode|
episode.compiledname = episode.filename.gsub(/[^0-9A-Za-z .]/, '').gsub(' ','_')
end
# Make sure necessary directories exist
FileUtils.mkdir_p('output/assets') unless File.directory?('output/assets')
FileUtils.mkdir_p('output/assets/mp3') unless File.directory?('output/assets/mp3')
FileUtils.mkdir_p('output/episode') unless File.directory?('output/episode')
# Copy over and process MP3 files
# Update index.html
layout = File.read('templates/layout.html')
layout = Erubis::Eruby.new(layout)
index_compiled = layout.result(config: $config, episodes: episodes) do
index = Erubis::Eruby.new(File.read('templates/index.html'))
index.result(config: $config, episodes: episodes, test: "hello, world") do |episode|
ep = Erubis::Eruby.new(File.read('templates/episode.html'))
ep.result(config: $config, episodes: episodes, episode: episode)
end
end
File.open('output/index.html', 'w') {|f| f.write(index_compiled) }
touchedfiles << 'index.html'
# Update episode pages
episodes.each do |episode|
layout = File.read('templates/layout.html')
layout = Erubis::Eruby.new(layout)
episode_compiled = layout.result(config: $config, episodes: episodes) do
ep = Erubis::Eruby.new(File.read('templates/episode.html'))
ep.result(config: $config, episodes: episodes, episode: episode)
end
File.open("output/#{episode.path(false)}", 'w') {|f| f.write(episode_compiled) }
touchedfiles << episode.path(false)
end
# Update iTunes RSS
itunes = File.read "templates/itunes.xml"
itunes = Erubis::Eruby.new(itunes)
itunes_compiled = itunes.result(config: $config, episodes: episodes)
File.open("output/itunes.xml", 'w') {|f| f.write(itunes_compiled) }
touchedfiles << "itunes.xml"
# Update General RSS
# Purge left over files
purge_output(touchedfiles)
end
def purge_output(touchedfiles, subdir = "")
Dir.foreach("output/#{subdir}") do |item|
next if item == '.' or item == '..'
p = "#{subdir}#{item}"
begin
File.delete "output/#{subdir}#{item}" unless touchedfiles.include? p
rescue Errno::EISDIR
purge_output touchedfiles, "#{p}/"
end
end
end
## Deployment stuff below
def deploy
touchedfiles = Array.new
deploy_r touchedfiles
# Purge left over files
purge_bucket touchedfiles
end
def deploy_r(touchedfiles, subdir = "")
puts "Deploying... " if subdir == ""
Dir.foreach("output/#{subdir}") do |item|
next if item == '.' or item == '..'
begin
touchedfiles << "#{subdir}#{item}"
upload("#{subdir}#{item}", "output/#{subdir}#{item}")
rescue Errno::EISDIR
deploy_r touchedfiles, "#{subdir}#{item}/"
end
end
end
def purge_bucket(touchedfiles)
bucket = AWS::S3::Bucket.find $bucketname
bucket.objects.each do |object|
object.delete unless touchedfiles.include? object.key
end
end
def filehash(filepath)
sha1 = Digest::SHA1.new
File.open(filepath) do|file|
buffer = ''
# Read the file 512 bytes at a time
while not file.eof
file.read(512, buffer)
sha1.update(buffer)
end
end
return sha1.to_s
end
def upload(objectname, filepath)
# Generate hash of file
hash = filehash filepath
# Get hash of version already uploaded, if available.
begin
object = AWS::S3::S3Object.find objectname, $bucketname
oldhash = object.metadata['hash']
rescue AWS::S3::NoSuchKey
# File not uploaded yet
oldhash = nil
end
unless hash == oldhash
# Don't reupload if file hasn't changed
puts "#{objectname}: Uploading"
AWS::S3::S3Object.store(objectname, open(filepath), $bucketname, access: :public_read, 'x-amz-meta-hash' => hash)
else
puts "#{objectname}: Not uploading, hasn't changed since last time."
end
end
def cd
compile
deploy
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment