Skip to content

Otter is a self-hosted bookmark manager made with Next.js and Supabase with Mastodon integration.

Notifications You must be signed in to change notification settings

mrmartineau/Otter

Repository files navigation


Otter

Otter is a self-hosted bookmark manager made with Next.js and Supabase with Mastodon integration.

Otter is released under the MIT license. PRs welcome! Follow @zander

FeaturesGetting startedDocsEcosystem

Features

  • Private bookmarking app with search, tagging and filtering
  • Dark/light colour modes
  • Mastodon integration - backup of your own toots as well as your favourite toots
  • Raycast extension to search your bookmarks, view recent bookmarks and create new ones
  • Chrome extension for easy bookmarking
  • Bookmarklet

Screenshots

Feed (dark mode)
Feed (light mode)
New bookmark
Search
Feed (showing tags sidebar)
Toots feed

Getting started

Prerequisites

  • pnpm - install with npm i -g pnpm
  • Vercel account and the Vercel CLI - install with npm i -g vercel
  • Supabase account and the Supabase CLI - install with npm i -g supabase
  • Cloudflare account (optional) - used for the page scraper and Mastodon to Supabase worker

Setup

  1. Fork this repo
  2. Go to database.new and create a new Supabase project. You will need the project ID (found in the project settings page) and the the database password for the next step.
  3. Link your Supabase project to your local dev environment: pnpm supabase:link
  4. Seed your database with pnpm supabase:setup
  5. Install npm dependencies with pnpm: pnpm install
  6. Create a new project on vercel and setup env vars (see below)
  7. To allow signups, set the value of ALLOW_SIGNUP in ./src/constants.ts to true
  8. Run the app locally using pnpm dev
  9. Visit http://localhost:5678 and create an account

Env vars

Set up the following env vars using either the Vercel CLI or through the Vercel project settings. Once they are added run vc env pull to pull them down to your local dev environment.

# Find these in your Supabase project settings > API
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_KEY=your-service-key # only needed for testing APIs using the `*.rest` files

PERSONAL_MASTODON_ACCESS_TOKEN=your-personal-app-mastodon-access-token
BOT_MASTODON_ACCESS_TOKEN=your-bot-app-mastodon-access-token
OTTER_API_TOKEN=your-otter-api-token

Docs

API Endpoints

Interactive API docs can be found in the various *.rest files in the /app/api directory.

  • POST /api/new - create new item in Otter
  • GET /api/new?url=https://example.com - quick create new item in Otter. Pass in a url query param and it will create a new item with that URL and includes its metadata too
  • GET /api/bookmarks - returns all bookmarks
  • GET /api/search?searchTerm=zander - search bookmark
  • POST /api/toot - A PostgreSQL trigger function calls this endpoint anytime a bookmark is created or edited which then creates a new toot on two of my Mastodon accounts (@otterbot@botsin.space & @zander@toot.cafe). It only sends a toot if the bookmark has the public column set to true.

Mastodon integration

Otter has the ability to auto-toot to 2 Mastodon accounts when a new bookmark is created or edited. This is done via a PostgreSQL trigger function that calls the /api/toot endpoint.

The trigger function below uses an environment variable in the Authorization header to ensure only the owner of the Otter instance can call the endpoint.

create trigger "toot-otter-items"
after insert
or
update on bookmarks for each row
execute function supabase_functions.http_request (
  'https://{your-otter-instance}/api/toot',
  'POST',
  -- replace {OTTER_API_TOKEN} with your own token
  '{"Content-type":"application/json","Authorization":"{OTTER_API_TOKEN}"}',
  '{}',
  '1000'
);

TODO:

  • document the PostgreSQL trigger function that calls the /api/toot endpoint

Bookmarks

Adding new bookmark types

  1. Add the new type to the types enum ALTER TYPE type ADD VALUE '???';
  2. Run pnpm run supabase:types to update the TypeScript types
  3. Add a new case to the TypeToIcon component
  4. Add a new TypeRadio component to the BookmarkForm component

Otter ecosystem

I use various other tools to make Otter even better:

License

MIT © Zander Martineau

Made by Zander • zander.wtfGitHubMastodon