1.2.0 • Published 4 months ago

astro-loader-goodreads v1.2.0

Weekly downloads
-
License
MIT
Repository
github
Last release
4 months ago

astro-loader-goodreads

npm version npm downloads License JSDocs bundle

Astro Goodreads How to use Goodreads data in Astro

Load Goodreads data for books in shelves/lists, user updates, and author blogs into Astro.

!NOTE astro-loader-goodreads uses the Astro Content Loader API to fetch data from Goodreads RSS feeds.

See the Usage section below for instructions on how to use the package to load the fetched Goodreads data into Astro Content Collections.


Table of Contents


Features

  • Load Bookshelves: Import your Goodreads shelves to showcase your reading list, books you've read, or want to read.
  • User Updates: Display your latest Goodreads activity including reading status updates, reviews, and likes.
  • Author Blogs: Fetch author blogs from Goodreads to display updates from your favorite authors.
  • Astro Content Collections: Seamlessly integrates with Astro's content collection system for type-safe data access.

Community Examples

Below are some examples of websites that use astro-loader-goodreads. If you wish to add your site to this list, open a pull request!

SitePageDescriptionSource
sadman.casadman.ca/aboutBooks I'm currently reading and have recently finished.

Installation

npm add astro-loader-goodreads

Usage

Loader Options

PropertyDescriptionRequiredDefault
urlThe URL of your Goodreads shelf, user, or author.-
refreshIntervalDaysNumber of days to cache data before fetching again from Goodreads.0

When refreshIntervalDays is set (e.g., to 7 for weekly updates), the loader will only fetch new data from Goodreads when that many days have passed since the last fetch. feat: Add optional loader option refreshIntervalDays. If not specified, no caching is done between builds (Astro's default data caching between page loads still applies).

Defining & Using Astro Content Collections

astro-loader-goodreads supports loading Goodreads data from 3 types of urls:

  1. Shelves: Load books from a Goodreads shelf.
  2. User Updates: Load a Goodreads user's updates feed.
  3. Author Blogs: Load a Goodreads author's blog.

In your content.config.ts or src/content/config.ts file, you can define your content collections using each type of URL with the goodreadsLoader function.

!NOTE For the full list of fields available for Astro content collections created using astro-loader-goodreads, see the Data Schema section below.


1. Goodreads Shelves

To load data for books from a Goodreads shelf, use the shelf's URL (e.g. https://www.goodreads.com/review/list/152185079-sadman-hossain?shelf=currently-reading). astro-loader-goodreads will convert it to the correct RSS feed URL automatically.

!IMPORTANT The RSS feed for a Goodreads shelf only includes the last 100 books added to that shelf. This means that if there are more than 100 books in a shelf, astro-loader-goodreads will not be able to retrieve them all.

You can, however, create multiple shelves (e.g. read-2025, read-2026, etc.) and then create a content collection for each shelf to get around this limitation.

// src/content/config.ts
import { defineCollection } from "astro:content";
import { goodreadsLoader } from "astro-loader-goodreads";

const currentlyReading = defineCollection({
  loader: goodreadsLoader({
    url: "https://www.goodreads.com/review/list/152185079-sadman-hossain?shelf=currently-reading",
    refreshIntervalDays: 7, // optional parameter; set to only fetch new data once per week
  }),
});

export const collections = { currentlyReading };
---
// src/pages/reading.astro
import { getCollection } from "astro:content";

const books = await getCollection("currentlyReading");
---

<h1>Books I'm Currently Reading</h1>

<div class="book-grid">
  {books.map((book) => (
    <div class="book-card">
      <img src={book.data.book_large_image_url} alt={`Cover of ${book.data.title}`} />
      <h2>{book.data.title}</h2>
      <p class="author">by {book.data.author_name}</p>
      {book.data.user_rating > 0 && (
        <p class="rating">My rating: {book.data.user_rating}/5</p>
      )}
      <a href={book.data.link} target="_blank" rel="noopener noreferrer">
        View on Goodreads
      </a>
    </div>
  ))}
</div>

<style>
  .book-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 2rem;
  }
  .book-card {
    border: 1px solid #eee;
    border-radius: 0.5rem;
    padding: 1rem;
    text-align: center;
  }
  .book-card img {
    max-width: 100%;
    height: auto;
  }
</style>

2. Goodreads User Updates

To load a Goodreads user's updates feed, use the user's profile URL (e.g. https://www.goodreads.com/user/show/152185079-sadman-hossain). astro-loader-goodreads will convert it to the correct RSS feed URL automatically.

!IMPORTANT The RSS feed for a Goodreads user's updates only includes the last 10 updates by that user. This means that astro-loader-goodreads cannot retrieve more than 10 updates for any single user.

// src/content/config.ts
import { defineCollection } from "astro:content";
import { goodreadsLoader } from "astro-loader-goodreads";

const userUpdates = defineCollection({
  loader: goodreadsLoader({
    url: "https://www.goodreads.com/user/show/152185079-sadman-hossain",
  }),
});

export const collections = { userUpdates };
---
// src/pages/activity.astro
import { getCollection } from "astro:content";

const updates = await getCollection("userUpdates");

// Sort updates by publication date (newest first)
const sortedUpdates = updates.sort((a, b) => 
  new Date(b.data.pubDate).getTime() - new Date(a.data.pubDate).getTime()
);
---

<h1>My Goodreads Activity</h1>

<div class="activity-feed">
  {sortedUpdates.map((update) => {
    const itemData = update.data.itemData;
    
    return (
      <div class="activity-item">
        <p class="date">{new Date(update.data.pubDate).toLocaleDateString()}</p>
        
        {itemData?.type === "ReadStatus" && (
          <div class="read-status">
            <img 
              src={itemData.bookImgUrl} 
              alt={`Cover of ${itemData.bookTitle}`} 
              width="50"
            />
            <div>
              <p>
                <strong>{itemData.readingStatus}</strong> 
                <a href={itemData.bookUrl}>{itemData.bookTitle}</a> 
                by {itemData.bookAuthor}
              </p>
            </div>
          </div>
        )}
        
        {itemData?.type === "Review" && (
          <div class="review">
            <img 
              src={itemData.bookImgUrl} 
              alt={`Cover of ${itemData.bookTitle}`} 
              width="50"
            />
            <div>
              <p>
                Rated <strong>{itemData.rating} stars</strong> for 
                <a href={itemData.bookUrl}>{itemData.bookTitle}</a> 
                by {itemData.bookAuthor}
              </p>
            </div>
          </div>
        )}
        
        {itemData?.type === "CommentReview" && (
          <div class="comment-review">
            <div>
              <p>
                Commented on <a href={itemData.reviewUrl}>{itemData.reviewUser}'s review</a> of 
                <a href={itemData.bookUrl}>{itemData.bookTitle}</a>:
              </p>
              <blockquote>"{itemData.comment}"</blockquote>
            </div>
          </div>
        )}
        
        {/* Add additional item types as needed */}
      </div>
    );
  })}
</div>

3. Goodreads Author Blogs

To load Goodreads author blog posts, use the author's URL (e.g. https://www.goodreads.com/author/show/3389.Stephen_King). astro-loader-goodreads will append the necessary parameters to fetch the blog RSS feed automatically.

// src/content/config.ts
import { defineCollection } from "astro:content";
import { goodreadsLoader } from "astro-loader-goodreads";

const authorBlog = defineCollection({
  loader: goodreadsLoader({
    url: "https://www.goodreads.com/author/show/3389.Stephen_King",
  }),
});

export const collections = { authorBlog };
---
// src/pages/author-updates.astro
import { getCollection } from "astro:content";

const posts = await getCollection("authorBlog");
---

<h1>Latest Updates from Stephen Kingn</h1>

<div class="blog-posts">
  {posts.map((post) => (
    <article class="blog-post">
      <h2>{post.data.title}</h2>
      <p class="date">Published: {new Date(post.data.pubDate).toLocaleDateString()}</p>
      {post.data.content && (
        <div class="content" set:html={post.data.content} />
      )}
      <a href={post.data.link}>Read on Goodreads</a>
    </article>
  ))}
</div>

Data Schema

Overview

The astro-loader-goodreads package provides three main schemas:

  1. BookSchema - For books from Goodreads shelves
  2. UserUpdateSchema - For user updates (with various activity types)
  3. AuthorBlogSchema - For author blog posts

1. BookSchema

This schema is used when loading data from a Goodreads shelf.

export const BookSchema = z.object({
  id: z.coerce.string(),
  title: z.coerce.string(),
  guid: z.string(),
  pubDate: z.string(),
  link: z.string(),
  book_id: z.coerce.string(),
  book_image_url: z.string(),
  book_small_image_url: z.string(),
  book_medium_image_url: z.string(),
  book_large_image_url: z.string(),
  book_description: z.string(),
  num_pages: z.string().optional(),
  author_name: z.string(),
  isbn: z.coerce.string(),
  user_name: z.string(),
  user_rating: z.number(),
  user_read_at: z.string(),
  user_date_added: z.string(),
  user_date_created: z.string(),
  user_shelves: z.string().optional(),
  user_review: z.string().optional(),
  average_rating: z.number(),
  book_published: z.coerce.string(),
});

Book Fields

FieldDescription
idUnique identifier for the book
titleBook title
guidGlobal unique identifier for this entry
pubDatePublication date of this entry in the feed
linkURL to the book's Goodreads page
book_idGoodreads ID for the book
book_image_urlURL to the book cover image
book_small_image_urlURL to small version of book cover (50×75 px)
book_medium_image_urlURL to medium version of book cover (65×98 px)
book_large_image_urlURL to large version of book cover (316×475 px)
book_descriptionDescription/synopsis of the book
num_pagesNumber of pages in the book (optional)
author_nameName of the book's author
isbnInternational Standard Book Number
user_nameUsername of who added the book to their shelf
user_ratingRating given by the user (0-5)
user_read_atDate when the user finished reading the book
user_date_addedDate when the book was added to the user's shelf
user_date_createdDate when this entry was created
user_shelvesList of shelves the user assigned to this book (optional)
user_reviewUser's review of the book (optional)
average_ratingAverage rating on Goodreads
book_publishedBook's original publication date

2. UserUpdateSchema

This schema is used when loading data from a Goodreads user's updates feed.

export const UserUpdateSchema = z.object({
  id: z.string(),
  title: z.string(),
  link: z.string().optional(),
  description: z.string().optional(),
  pubDate: z.string(),
  itemType: z.string().optional(),
  itemData: ItemDataSchema.optional()
});

UserUpdateSchema Item Types

The itemData field contains a discriminated union based on the type field:

AuthorFollowing

When a user follows an author:

{
  type: "AuthorFollowing",
  followId: string,
  userUrl: string, 
  authorId: string
}

UserStatus

When a user reports progress on a book:

{
  type: "UserStatus",
  userUrl: string,
  percentRead: string,
  bookUrl: string,
  bookTitle: string,
  bookAuthor: string,
  bookImgUrl: string
}

ReadStatus

When a user changes their reading status:

{
  type: "ReadStatus",
  userUrl: string, 
  readingStatus: string, // 'started reading', 'wants to read', or 'finished reading'
  bookUrl: string,
  bookTitle: string,
  bookAuthor: string,
  bookImgUrl: string
}

Review

When a user posts a review:

{
  type: "Review",
  userUrl: string,
  rating: number,
  bookUrl: string,
  bookTitle: string,
  bookAuthor: string,
  bookImgUrl: string
}

LikeReview

When a user likes someone's review:

{
  type: "LikeReview",
  userUrl: string,
  reviewUrl: string,
  reviewUser: string,
  bookUrl: string,
  bookTitle: string,
  bookImgUrl: string
}

LikeReadStatus

When a user likes someone's read status:

{
  type: "LikeReadStatus",
  userUrl: string,
  readStatusUser: string,
  readStatusUserImgUrl: string,
  readStatus: string,
  bookUrl: string,
  bookTitle: string
}

CommentStatus

When a user comments on a status:

{
  type: "CommentStatus",
  userUrl: string,
  statusUrl: string,
  statusUser: string,
  comment: string
}

CommentReview

When a user comments on a review:

{
  type: "CommentReview",
  userUrl: string,
  reviewUrl: string,
  reviewUser: string,
  bookUrl: string,
  bookTitle: string,
  bookAuthor: string,
  comment: string
}

3. AuthorBlogSchema

This schema is used when loading data from a Goodreads author's blog.

export const AuthorBlogSchema = z.object({
  id: z.string(),
  title: z.string(),
  link: z.string(),
  description: z.string(),
  pubDate: z.string(),
  author: z.string().optional(),
  content: z.string().optional(),
});

AuthorBlogSchema Fields

FieldDescription
idUnique identifier for the blog post
titleBlog post title
linkURL to the blog post
descriptionRaw HTML description of the blog post
pubDatePublication date
authorAuthor's name (if available)
contentMain content of the blog post (if available)

License

astro-loader-goodreads is MIT licensed.


Built with ♥ by @sadmanca!

1.2.0

4 months ago

1.1.1

4 months ago

1.1.0

4 months ago

0.2.1

5 months ago

0.2.0

5 months ago

0.1.0

5 months ago