Created
January 1, 2012 17:28
-
-
Save founddrama/1547848 to your computer and use it in GitHub Desktop.
Goodreads.com reading timeline (stub)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function($){ | |
$(document).ready(function(){ | |
var data = window['data'], | |
// for reviews: | |
rate = function(r){ | |
if (r === 0) { | |
return '<em>unrated</em>'; | |
} | |
var str = ''; | |
// Stars... | |
while (str.length < r) { | |
str += '\u2605'; | |
} | |
while (str.length < 5) { | |
str += '\u2606'; | |
} | |
return str; | |
}; | |
$('.review').tipsy({ | |
delayOut: 1000, | |
gravity: 'w', | |
fade:true, | |
html:true, | |
title: function(){ | |
var book = data[this.getAttribute('id')]; | |
return '<div style="width:125px;">' + book.started + ' to ' + book.finished + '<br/>' + | |
'<a href="' + book.url + '" title="View ' + book.title + ' on Goodreads.com">' + | |
'<img src="' + book.cover + '" /><br/><em>' + book.title + '</em><br/>by ' + book.author + | |
'<br/>' + rate(book.rating) +'</a></div>'; | |
} | |
}); | |
$('#preload-shim').append(function(){ | |
var o, i, imgs = []; | |
for (o in data) { | |
i = new Image(); | |
i.src = data[o].cover; | |
imgs.push(i); | |
} | |
return imgs; | |
}); | |
}); | |
})(jQuery); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//#!/usr/bin/env groovy | |
// commented out for the Gist syntax highlighting | |
import static java.util.Calendar.YEAR | |
import groovy.text.SimpleTemplateEngine | |
def usage = """\nUSAGE: | |
Give it your API key, your Goodreads.com user ID, and the name of the shelf | |
you want to convert into a timeline: | |
./GetTimeline.groovy api_key user_id [shelf-name] | |
The default shelf name is '2011' | |
""" | |
if (args.grep('--help') || args.grep('-h') || args.grep('-?')) { | |
println usage | |
System.exit(0) | |
} | |
def apiKey | |
def user | |
def shelf | |
def assignFromArgs = { theArgs -> | |
(theArgs.size() >= 2) { | |
apiKey = theArgs[0] | |
user = theArgs[1] | |
shelf = theArgs.last() : '2011' | |
} else { | |
println "[ERROR] You did not supply the correct number of arguments!\n\n${usage}" | |
System.exit(1) | |
} | |
} | |
assignFromArgs(args as List) | |
def url = "http://www.goodreads.com/review/list?v=2&key=${apiKey}&id=${user}&shelf=${shelf}&sort=date_read&per_page=100&order=a" | |
def sanitizeDate(def dateStr) { | |
Date d = new Date(0).parse('EEE MMM dd HH:mm:ss Z yyyy', dateStr) | |
return d | |
} | |
def reviewList = [] | |
try { | |
def xml = new XmlParser().parse( url.toURL().newReader() ) | |
xml.reviews.review.each { | |
def summary = [ | |
id: it.id.text(), | |
url: it.url.text(), | |
title: it.book.title.text().replaceAll(/(\s\(.+\s#\d.*\))$/, ''), | |
cover: it.book.image_url?.text() ?: null, | |
authors: it.book.authors.toList().collect { a -> a.author.name.text() }, | |
started: it.started_at?.text() ? sanitizeDate(it.started_at?.text()) : new Date().parse('yyyy-MM-dd', '2011-01-01'), | |
finished: it.read_at?.text() ? sanitizeDate(it.read_at.text()) : new Date().parse('yyyy-MM-dd', '2011-12-31'), | |
read_count: it.read_count?.text() ? (it.read_count.text() as String).split(' ').first().replaceAll(/[\D]/, '') as int : 0, | |
rating: it.rating?.text() as int | |
] | |
// My special exception for 'The Joy of Clojure' :-\ | |
if (shelf == '2011' && summary.title.contains('Joy') && summary.title.contains('Clojure')) { | |
summary.started = new Date().parse('yyyy-MM-dd', '2011-07-07') | |
summary.finished = new Date().parse('yyyy-MM-dd', '2011-12-31') | |
} | |
reviewList << summary | |
} | |
} catch(Throwable e) { | |
println "Something went wrong trying to parse ${url}: ${e}" | |
} | |
reviewList.sort { a, b -> | |
a.started > b.started ? 1 : -1 | |
} | |
def divClassBuilder = { review -> | |
def cls = ['review'] | |
if (review.read_count < 2) { | |
cls << 'new' | |
} | |
return "${cls.join(' ')}" | |
} | |
def shelfYear = ({ y -> | |
try { | |
return y as int | |
} catch(e){ | |
return new Date()[YEAR] as int | |
} | |
})(shelf) | |
def styleBuilder = { review -> | |
def started = review.started.format('D') as int | |
def finished = review.finished.format('D') as int | |
if (review.started[YEAR] < shelfYear) { | |
// Jan 1st | |
started = 1 | |
} else if (review.finished[YEAR] > shelfYear) { | |
finished = new Date().parse('yyyy-M-d', "${review.started[YEAR]}-12-31").format('D') as int | |
} | |
def style = "" | |
style += "top:${(started - 1) * 10}px;" | |
style += "height:${((finished - started) * 10) + 10};" | |
return style | |
} | |
def markup = '' | |
def jsData = [] | |
reviewList.each { | |
jsData << """'${it.id}':{ | |
started: '${it.started.format('M/d')}', | |
finished: '${it.finished.format('M/d')}', | |
rating: ${it.rating}, | |
title: '${it.title.replaceAll(/[']/, '\\\\\'')}', | |
author: '${it.authors.first().replaceAll(/[']/, '\\\\\'')}', | |
cover: '${it.cover}', | |
url: '${it.url}' | |
}""" | |
markup += """<div class="${divClassBuilder(it)}" style="${styleBuilder(it)}" title="<img src='${it.cover}' /><br/><em>${it.title}</em> by ${it.authors.first()}" id="${it.id}"> </div>\n""" | |
} | |
File f = new File("target/${shelf}.htm") | |
def tpl = new File('templates/timeline.template').getText('UTF-8') | |
def binding = [jsData: "{${jsData.join(',')}}", shelf: shelf, markup: markup] | |
SimpleTemplateEngine engine = new SimpleTemplateEngine() | |
f.write(engine.createTemplate(tpl).make(binding).toString()) | |
System.exit(0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html, body { | |
font-family: 'Lucida Grand' 'Helvetica' 'Verdana' sans-serif; | |
font-size: 12px; | |
margin: 0; | |
padding: 0; | |
} | |
.masthead { | |
color: rgb(33,86,37); | |
border-bottom: 3px double rgb(33,86,37); | |
} | |
.masthead h1 { | |
font-size: 3em; | |
margin: 1em 20px; | |
} | |
.footer { | |
position: relative; | |
} | |
.footer .badge { | |
position: absolute; | |
bottom: 2px; | |
right: 2px; | |
height: 41px; | |
width: 130px; | |
background: transparent url(goodreads-badge-read-reviews.png) no-repeat scroll center center; | |
} | |
a, a:hover, a:visited { | |
color: #E3DFC9; | |
text-decoration: none; | |
} | |
.month-marker { | |
position: absolute; | |
left: 0; | |
right: 0; | |
height: 0px; | |
border-top: 1px dashed rgb(56, 33, 16); | |
border-top-color: rgba(56, 33, 16, 0.8); | |
} | |
.month-marker span { | |
display: block; | |
width: 100px; | |
padding: 4px 10px; | |
background: rgb(56, 33, 16); | |
background: rgba(56, 33, 16, 0.8); | |
color: rgb(250, 250, 250); | |
color: rgba(250, 250, 250, 0.8); | |
} | |
#jan { top: 0; border: none;} | |
#feb { top: 310px; } | |
#mar { top: 590px; } | |
#apr { top: 900px; } | |
#may { top: 1200px; } | |
#jun { top: 1510px; } | |
#jul { top: 1810px; } | |
#aug { top: 2120px; } | |
#sep { top: 2430px; } | |
#oct { top: 2730px; } | |
#nov { top: 3040px; } | |
#dec { top: 3340px; } | |
.reviews-ct { | |
border: 1px solid rgb(56, 33, 16); | |
border-color: rgba(56, 33, 16, 0.8); | |
margin: 1px auto 50px; | |
position: relative; | |
overflow: hidden; | |
height: 3650px; | |
width: 900px; | |
background: #E3DFC9; | |
background-image: linear-gradient(bottom, rgb(244,243,235) 28%, rgb(227,223,201) 82%); | |
background-image: -o-linear-gradient(bottom, rgb(244,243,235) 28%, rgb(227,223,201) 82%); | |
background-image: -moz-linear-gradient(bottom, rgb(244,243,235) 28%, rgb(227,223,201) 82%); | |
background-image: -webkit-linear-gradient(bottom, rgb(244,243,235) 28%, rgb(227,223,201) 82%); | |
background-image: -ms-linear-gradient(bottom, rgb(244,243,235) 28%, rgb(227,223,201) 82%); | |
} | |
.review { | |
position: relative; | |
float: left; | |
width: 20px; | |
border-radius: 6px / 4px; | |
background: rgb(33, 86, 37); | |
background: rgba(33, 86, 37, 0.9); | |
background-image: linear-gradient(right, rgb(33,86,37) 28%, rgb(12,31,13) 82%); | |
background-image: -o-linear-gradient(right, rgb(33,86,37) 28%, rgb(12,31,13) 82%); | |
background-image: -moz-linear-gradient(right, rgb(33,86,37) 28%, rgb(12,31,13) 82%); | |
background-image: -webkit-linear-gradient(right, rgb(33,86,37) 28%, rgb(12,31,13) 82%); | |
background-image: -ms-linear-gradient(right, rgb(33,86,37) 28%, rgb(12,31,13) 82%); | |
} | |
.review:hover { | |
box-shadow: 0 12px 8px rgba(157, 217, 161, 0.9); | |
} | |
#preload-shim { | |
height: 1px; | |
width: 1px; | |
position: absolute; | |
left: -9999px; | |
overflow: hidden; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | |
<link rel="stylesheet" type="text/css" href="assets/timeline.css" /> | |
<link rel="stylesheet" type="text/css" href="assets/tipsy.css" /> | |
<script type="text/javascript" charset="UTF-8"> | |
data = ${jsData}; | |
</script> | |
</head> | |
<body> | |
<div class="masthead"> | |
<h1>${shelf} reading list</h1> | |
</div> | |
<div class="reviews-ct"> | |
${markup} | |
<div class="month-marker" id="jan"><span>January</span></div> | |
<div class="month-marker" id="feb"><span>February</span></div> | |
<div class="month-marker" id="mar"><span>March</span></div> | |
<div class="month-marker" id="apr"><span>April</span></div> | |
<div class="month-marker" id="may"><span>May</span></div> | |
<div class="month-marker" id="jun"><span>June</span></div> | |
<div class="month-marker" id="jul"><span>July</span></div> | |
<div class="month-marker" id="aug"><span>August</span></div> | |
<div class="month-marker" id="sep"><span>September</span></div> | |
<div class="month-marker" id="oct"><span>October</span></div> | |
<div class="month-marker" id="nov"><span>November</span></div> | |
<div class="month-marker" id="dec"><span>December</span></div> | |
</div> | |
<div class="footer"> | |
<a href="http://www.goodreads.com/"><div class="badge"></div></a> | |
<div id="preload-shim"></div> | |
</div> | |
<script type="text/javascript" src="assets/jquery.min.js"></script> | |
<script type="text/javascript" src="assets/jquery.tipsy.js"></script> | |
<script type="text/javascript" src="assets/br-init.js"></script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See:
http://founddrama.net/static/2011-reading-list.htm