Creare un widget per Goodreads con gli ultimi libri letti
Goodreads è un’ottima (e più flessibile) alternativa al famoso Anobii, che permette di catalogare i propri libri, recensirli, ricevere consigli su libri affini ai propri interessi.
A differenza di Anobii, Goodreads offre delle API più elaborate, e che ci possono permettere di creare un widget da mettere sul nostro sito, per mostrare gli ultimi libri letti, ed il libro che si sta leggendo adesso (qualora si stia leggendo un libro, e si trovi nello scaffale “currently-reading” di Goodreads).
Come mostrato nell’immagine all’inizio del post, il widget mostra le copertine dei nostri libri e, passando con la freccina del mouse su uno di questi, apparirà un pop-up che mostrerà il titolo, l’autore, e la descrizione del libro.
Inoltre, ho aggiunto un po’ di codice CSS (che NON funziona, purtroppo, con Internet Explorer 9) per far ruotare leggermente la copertina del libro, quando la freccina del mouse ci passa sopra.
Cliccando su un libro, si aprirà la corrispondente pagina su Goodreads.
Dopo esserci registrati sul sito ed aver inserito i nostri libri, andiamo su http://www.goodreads.com/api/keys per recuperare la nostra API Key.
Andiamo a vedere il codice del widget:
<?php /* Goodreads.com PHP widget for websites. It shows the last $number_books read books or,if there's currently a book you're reading in "currently-reading" bookshelf, display it together with $number_books-1 read books. Insert your API key, your Goodreads userid, the number of books to show, the expiration of the cachefile and the cachefile name. Book covers images are shown. Title, author and description (120 characters) are shown in the tooltip that appears when you hover on one of the books. Also, the date you started reading the book in the "currently-reading" shelf is displayed. Descriptions are not shown in Internet Explorer because it's a crappy browser and doesn't support break lines in the tooltips. Please respect Goodreads API terms! (c) Flapane.com - Oct-2013*/ $api_key = "yourapikey"; //goodreads api key $number_books = "5"; //how many books from "read" shelf $user_id = "youruserid"; //goodreads user id $expiretime=24; // cache expire time in hours. Goodreads does not allow more than 1 day $cachename="goodreads.cache"; //name of the cachefile function limitString($string, $limit = 120) { //shorten book descriptions but do not cut words. From Stackoverflow // Return early if the string is already shorter than the limit if(strlen($string) < $limit) {return $string;} $regex = "/(.{1,$limit})\b/"; preg_match($regex, $string, $matches); return $matches[1]; } //do not mess with the next lines!!! if (!file_exists($cachename)) { //create the cachefile if it doesn't exist $create = fopen($cachename, 'w'); chmod ("$cachename", 0644); //set chmod 644 fclose($create); } // Is the file older than $expiretime, or the file is new/empty? $FileAge = time() - filectime($cachename); // Calculate file age in seconds if ($FileAge > ($expiretime * 3600) || 0 == filesize($cachename)) { $handle = fopen($cachename, 'wb'); $read_books_path = "http://www.goodreads.com/review/list/".$user_id.".xml?key=".$api_key."&v=2&shelf=read&sort=date_read&order=d&page=1&per_page=".$number_books; $read_books_xml_query = file_get_contents($read_books_path); $read_books_json_array = json_decode(json_encode((array)simplexml_load_string($read_books_xml_query)),1); //from http://gilbert.pellegrom.me/php-quick-convert-xml-to-array/ sleep(1); //Goodreads allows 1 API call per second $reading_books_path = "http://www.goodreads.com/review/list/".$user_id.".xml?key=".$api_key."&v=2&shelf=currently-reading&sort=date_read&order=d&page=1&per_page=1"; //get last currently reading book $reading_books_xml_query = file_get_contents($reading_books_path); $reading_books_json_array = json_decode(json_encode((array)simplexml_load_string($reading_books_xml_query)),1); //from http://gilbert.pellegrom.me/php-quick-convert-xml-to-array/ for($i=0; $i<$number_books; $i++){ $read_titles[$i] = $read_books_json_array['reviews']['review'][$i]['book']['title']; $read_links[$i] = $read_books_json_array['reviews']['review'][$i]['book']['link']; $read_authors[$i] = $read_books_json_array['reviews']['review'][$i]['book']['authors']['author']['name']; $read_cover_images[$i] = $read_books_json_array['reviews']['review'][$i]['book']['image_url']; if (!empty($read_books_json_array['reviews']['review'][$i]['book']['description'])) //avoid empty descriptions { $read_descriptions[$i] = limitString(strip_tags($read_books_json_array['reviews']['review'][$i]['book']['description'])) . "[...]"; //strip html tags and cut description $read_descriptions[$i] = str_replace("\"", "'", $read_descriptions[$i]); //avoid double quotes } else $read_descriptions[$i] = "No description/Nessuna descrizione"; } if (!empty($reading_books_json_array['reviews']['review']['book'])) //are you currently reading any book and is it in "currently-reading" shelf? { $reading_titles = $reading_books_json_array['reviews']['review']['book']['title']; $reading_links = $reading_books_json_array['reviews']['review']['book']['link']; $reading_authors = $reading_books_json_array['reviews']['review']['book']['authors']['author']['name']; $reading_cover_images = $reading_books_json_array['reviews']['review']['book']['image_url']; $reading_start_date = $reading_books_json_array['reviews']['review']['started_at']; $reading_descriptions = $reading_books_json_array['reviews']['review']['book']['description']; if (!empty($reading_start_date)) //avoid empty "date I started this book" fields { $tz = new DateTimeZone('GMT'); $date = new DateTime($reading_start_date); $date->setTimeZone($tz); $reading_start_date = '- Started on '.$date->format('l, j M Y g:i:s A T'); //date you started reading the current book in UTC time } if (!empty($reading_descriptions)) //avoid empty descriptions { $reading_descriptions = limitString(strip_tags($reading_books_json_array['reviews']['review']['book']['description'])) . "[...]"; //strip html tags and cut description if (isset($read_descriptions[$i])){ $read_descriptions[$i] = str_replace("\"", "'", $read_descriptions[$i]); //avoid double quotes } } else $reading_descriptions = "No description/Nessuna descrizione"; //show the "currently-reading" book and the $number_books-1 most recently read books $data[0] = "<div class='goodreads-widget'>"; $data[1] = "<a href='$reading_links' target='_blank' title=\"$reading_authors - $reading_titles $reading_start_date Desc: $reading_descriptions\"><img src='$reading_cover_images' alt=\"$reading_authors - $reading_titles\" /></a>"; for($i=0; $i<$number_books-1; $i++){ $data[2+$i] = "<a href='$read_links[$i]' target='_blank' title=\"$read_authors[$i] - $read_titles[$i] Desc: $read_descriptions[$i]\"><img src='$read_cover_images[$i]' alt=\"$read_authors[$i] - $read_titles[$i]\" /></a>"; } $data[$number_books+1] = "</div>"; } else { //else show only $number_books "read" books $data[0] = "<div class='goodreads-widget'>"; for($i=0; $i<$number_books; $i++){ $data[1+$i] = "<a href='$read_links[$i]' target='_blank' title=\"$read_authors[$i] - $read_titles[$i] Desc: $read_descriptions[$i]\"><img src='$read_cover_images[$i]' alt=\"$read_authors[$i] - $read_titles[$i]\" /></a>"; } $data[$number_books+1] = "</div>"; } foreach($data as $value){ //write the output to the cachefile fwrite($handle, $value); } fclose($handle); } //cachefile is fresh enough... outputting data $data_cache=file_get_contents($cachename); echo $data_cache; ?>
Ed il relativo codice CSS:
<style type="text/css"> .goodreads-widget img { width: 98px; height: 160px; border:0px; -webkit-transition: all 0.5s ease; -moz-transition: all 0.5s ease; -o-transition: all 0.5s ease; -ms-transition: all 0.5s ease; transition: all 0.5s ease; } .goodreads-widget img:hover { -webkit-transform: rotate(-10deg); -moz-transform: rotate(-10deg); -o-transform: rotate(-10deg); -ms-transform: rotate(-10deg); transform: rotate(-10deg); -sand-transform: rotate(-10deg); } </style>
Come ho scritto nei commenti, è sufficiente inserire la propria API Key ($api_key), il numero di libri da mostrare ($number_books), il proprio user id di Goodreads ($user_id), il tempo massimo di durata del file di cache ($expiretime)(Goodreads non permette di salvare i dati per più di 24 ore), ed il nome del file di cache ($cachename).
Consiglio di leggere con attenzione le condizioni d’uso di Goodreads (clicca qui), dove c’è scritto cosa fare per non violare i termini d’uso.
Lo script recupera il numero di libri letti desiderato ($number_books), e va a controllare se, al momento, stiamo leggendo un libro (che, quindi, si troverà nello scaffale currently-reading di Goodreads).
Se stiamo leggendo un libro, lo script mostrerà questo libro, e gli ultimi $number_books-1 libri letti.
Se in questo momento non stiamo leggendo alcun libro, lo script mostrerà gli ultimi $number_books letti.
Le API restituiscono risposte in XML, ma io, per praticità e mia preferenza, ho preferito convertirle in JSON.
Nel file di cache verrà salvato solo il codice HTML del widget, in modo da minimizzare le dimensioni del file.
Consigli? Problemi? Avete inserito il widget sul vostro sito? Lasciate pure un commento! 🙂