A Shiny New Website

It’s been over 8 years since I last switched web platforms for ckdake.com, and it was time for a change. We are putting Gallery into hibernation, Drupal 6 is not going to get any more security updates once Drupal 8 is out (which should be soon), and the ongoing server/backup costs of keeping 130GB of photos on my site is not cheap.

At work, we recently launched a new bignerdranch.com, and my team did a fantastic job of building it as a ‘static’ site using jekyll. This included migrating a bunch of legacy Python, PHP, and Ruby code and an old Wordpress site.

With fantastic services like Flickr for photos and Vimeo for video, I set out to migrate my photos to Flickr and build a simple and fast ‘static’ site for ckdake.com. Here it is! The theme still needs a lot of work which is fine, and nanoc has been a lot of fun to get up and running.

Migrating Photos to Flickr

Flickr has a pretty straightforward API, and the Flickraw gem makes writing ruby code to talk to Flickr pretty easily. A few weeks ago I started on this and published the script that migrated my ~25,000 photos to Flickr here: gallery2flickr.rb.

This took about a week to run, and afterwards I spent a good bit of time properly naming sets, changing privacy settings, and copying over captions from my ‘stream’ abums. More time on the script could have automated some of this, but it’s done.

Getting Flickr Photos displayed here was a pretty straightforward block of Ruby code:

require 'flickraw'
FlickRaw.api_key=ENV['FLICKR_KEY']
FlickRaw.shared_secret=ENV['FLICKR_SECRET']
flickr.access_token=ENV['FLICKR_ACCESS_TOKEN']
flickr.access_secret=ENV['FLICKR_ACCESS_SECRET']
# token = flickr.get_request_token
# auth_url = flickr.get_authorize_url(token['oauth_token'], :perms => 'delete')
#
# puts "Open this url in your process to complete the authication process : #{auth_url}"
# puts "Copy here the number given when you complete the process."
# verify = gets.strip
#
# begin
# flickr.get_access_token(token['oauth_token'], token['oauth_token_secret'], verify)
# login = flickr.test.login
# puts "You are now authenticated as #{login.username} with token #{flickr.access_token} and secret #{flickr.access_secret}"
# rescue FlickRaw::FailedResponse => e
# puts "Authentication failed : #{e.msg}"
# end
$photosets = nil
def recent_flickr_sets_html(count)
html = ''
$photosets ||= flickr.photosets.getList
(0..(count.to_i - 1)).each do |i|
if $photosets[i]['visibility_can_see_set'] == 1
html = html + flickr_set_to_html(
{
title: $photosets[i]['title'],
id: $photosets[i]['id'],
primary: $photosets[i]['primary'],
secret: $photosets[i]['secret'],
server: $photosets[i]['server'],
farm: $photosets[i]['farm'],
}
)
end
end
html
end
def flickr_set_to_html(set)
"<a href='https://www.flickr.com/photos/ckdake/sets/#{set[:id]}'><img src='https://farm#{set[:farm]}.staticflickr.com/#{set[:server]}/#{set[:primary]}_#{set[:secret]}_q.jpg' /></a>"
end
view raw flickr.rb hosted with ❤ by GitHub

Pulling in Vimeo

Vimeo was really easy to pull in to, and the end result looks much better than the JavaScript widget I was using. It’s Ruby:

require 'vimeo'
$videos = nil
def recent_vimeo_videos_embed_html(count)
html = ''
$videos ||= Vimeo::Simple::User.videos("ckdake")
(0..(count.to_i - 1)).each do |i|
html = html + vimeo_video_to_embed_html(
{
id: $videos[i]['id'],
width: $videos[i]['width'],
height: $videos[i]['height']
}
)
end
html
end
def recent_vimeo_videos_link_html(count)
html = ''
$videos ||= Vimeo::Simple::User.videos("ckdake")
(0..(count.to_i - 1)).each do |i|
html = html + vimeo_video_to_link_html(
{
title: $videos[i]['title'],
thumbnail: $videos[i]['thumbnail_medium'],
url: $videos[i]['url']
}
)
end
html
end
def vimeo_video_to_link_html(info)
"<div><a href='#{info[:url]}'><img src='#{info[:thumbnail]}'><br />#{info[:title]}</div>"
end
def vimeo_video_to_embed_html(info)
"<iframe src='//player.vimeo.com/video/#{info[:id]}' width='#{info[:width].to_i/4}' height='#{info[:height].to_i/4}' frameborder='0' webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>"
end
view raw vimeo.rb hosted with ❤ by GitHub

Preserving content and URLs

Getting content out of Drupal was a little bit more involved, and I didn’t spend the time to match up the ‘format’ of blog posts with file extensions or a content formatter. That might be nice, but I’m ok just fixing HTML files by hand when I notice something wonky. This script pulled out my content:

<?php
date_default_timezone_set('America/New_York');
$mysqli = new mysqli('', '', '', '');
if ($mysqli->connect_error) {
die('Connect Error (' . $mysqli->connect_errno . ') '
. $mysqli->connect_error);
}
if (mysqli_connect_error()) {
die('Connect Error (' . mysqli_connect_errno() . ') '
. mysqli_connect_error());
}
echo 'Success... ' . $mysqli->host_info . "\n";
$to_export = array();
if ($result = $mysqli->query("SELECT * FROM node")) {
while ($row = $result->fetch_assoc()) {
$to_export[$row['nid']] = $row;
$to_export[$row['nid']]['created_at'] = strftime("%Y-%m-%d %T %z", $row['created']);
}
}
# get their URLs and map to a filename
if ($result = $mysqli->query("SELECT * FROM url_alias")) {
while ($row = $result->fetch_assoc()) {
$matches = array();
if (preg_match('/node\/(\d+)/', $row['src'], $matches)) {
if ($to_export[$matches[1]]) {
$to_export[$matches[1]]['path'] = $row['dst'];
}
}
}
}
foreach ($to_export as $post) {
$vid = $post['vid'];
if ($result = $mysqli->query("SELECT * FROM node_revisions WHERE vid = $vid")) {
while ($row = $result->fetch_assoc()) {
$to_export[$row['nid']]['body'] = $row['body'];
}
}
}
foreach ($to_export as $post) {
if (array_key_exists('path', $post)) {
$title = $post['title'];
$created_at = $post['created_at'];
$body = $post['body'];
$the_post = <<<EOF
---
title: $title
created_at: $created_at
kind: article
---
$body
EOF;
file_put_contents($post['path'], $the_post);
}
}
$mysqli->close();
?>

And here is the full ‘Rules’ file for nanoc that keeps around my old blog and page URLs. Note that nanoc by default does things like ‘/folder/page/index.html’ so I’ve configured it to do ‘/folder/page.html’ instead.

#!/usr/bin/env ruby
# A few helpful tips about the Rules file:
#
# * The string given to #compile and #route are matching patterns for
# identifiers--not for paths. Therefore, you can’t match on extension.
#
# * The order of rules is important: for each item, only the first matching
# rule is applied.
#
# * Item identifiers start and end with a slash (e.g. “/about/” for the file
# “content/about.html”). To select all children, grandchildren, … of an
# item, use the pattern “/about/*/”; “/about/*” will also select the parent,
# because “*” matches zero or more characters.
compile 'blog/feed' do
filter :erb
end
route 'blog/feed' do
'/rss.xml'
end
compile '/blog/*' do
if item[:extension] == 'md'
filter :kramdown
else
filter :erb
end
layout 'post'
end
route '/blog/*' do
y,slug = /([0-9]+)(.+)/.match(item.identifier).captures
"/content/#{y}#{slug[0..-2]}.html"
end
compile '*' do
if item[:extension] == 'md'
filter :kramdown
layout 'default'
elsif item[:extension] == 'css'
# don’t filter stylesheets
elsif item.binary?
# don’t filter binary items
else
filter :erb
layout 'default'
end
end
route '*' do
if item[:extension] == 'css'
# Write item with identifier /foo/ to /foo.css
item.identifier.chop + '.css'
elsif item.binary?
# Write item with identifier /foo/ to /foo.ext
item.identifier.chop + '.' + item[:extension]
else
if item.identifier == "/"
'/index.html'
else
item.identifier[0..-2] + '.html'
end
# Write item with identifier /foo/ to /foo/index.html
# item.identifier + '.html'
end
end
layout '*', :erb
view raw Rules.rb hosted with ❤ by GitHub

Onward

There is a mess of a UI to clean up, a pile of files to sort through, broken links to fix, etc. There are some PHP things that I need to figure out what to do with, and some shiny JavaScript libraries I want to play with. The ‘Projects’ section here is going to get some link-breaking cleanup as well, so stay tuned.