Skip to content

Instantly share code, notes, and snippets.

@jenny-codes
Created October 17, 2025 13:56
Show Gist options
  • Select an option

  • Save jenny-codes/19aa14b57672c8892d30003e6f0e2b5b to your computer and use it in GitHub Desktop.

Select an option

Save jenny-codes/19aa14b57672c8892d30003e6f0e2b5b to your computer and use it in GitHub Desktop.
Import StoryGraph data to Goodreads
#!/usr/bin/env ruby
# frozen_string_literal: true
# Usage:
# 1. Download storygraph data from https://app.thestorygraph.com/user-export
# 2. Run ./import-storygraph-data-to-goodreads FILEPATH
# 3. Upload the generated file to Goodreads https://www.goodreads.com/review/import
require 'csv'
require 'date'
IMPORT_DATE = Date.today.to_s
STORYGRAPH_TO_GOODREADS = {
"ISBN/UID" => ->(val) { ["ISBN", val] },
"Read Status" => ->(val) { ["Shelves", val] },
"Date Added" => ->(val) { ["Date Added", val&.gsub("/", "-")] },
"Last Date Read" => ->(val) { ["Date Read", val&.gsub("/", "-")]},
"Star Rating" => ->(val) { ["My Rating", val] },
"Review" => ->(val) { ["My Review", val] },
"Tags" => ->(val) { ["Bookshelves", "imported-#{IMPORT_DATE}"] },
}
GOODREAD_HEADERS = STORYGRAPH_TO_GOODREADS.values.map { |fn| fn.call(nil).first }
def main(storygraph_source_path)
CSV.open(
"csv-for-goodreads-#{IMPORT_DATE}.csv",
'w',
write_headers: true,
headers: GOODREAD_HEADERS
) do |output|
CSV.open(storygraph_source_path, headers: true) do |input|
input.each do |row|
output << STORYGRAPH_TO_GOODREADS.map do |key, fn|
fn.call(row[key]).last
end
end
end
end
end
main ARGV.first
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment