{"id":50211644,"url":"https://github.com/spotify/save-to-spotify","last_synced_at":"2026-06-09T18:01:56.451Z","repository":{"id":356305636,"uuid":"1205137798","full_name":"spotify/save-to-spotify","owner":"spotify","description":"Command line interface to save your personal media to Spotify.","archived":false,"fork":false,"pushed_at":"2026-06-09T12:21:06.000Z","size":177,"stargazers_count":363,"open_issues_count":8,"forks_count":17,"subscribers_count":7,"default_branch":"main","last_synced_at":"2026-06-09T14:12:31.881Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spotify.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-08T17:10:12.000Z","updated_at":"2026-06-08T11:16:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/spotify/save-to-spotify","commit_stats":null,"previous_names":["spotify/save-to-spotify"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/spotify/save-to-spotify","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fsave-to-spotify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fsave-to-spotify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fsave-to-spotify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fsave-to-spotify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spotify","download_url":"https://codeload.github.com/spotify/save-to-spotify/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fsave-to-spotify/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34118757,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-26T06:00:26.942Z","updated_at":"2026-06-09T18:01:56.438Z","avatar_url":"https://github.com/spotify.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# Save to Spotify\n\nA command-line tool for saving audio content to Spotify. Built for agents and automation, generate a daily briefing, language lesson, or meeting recap, then push it to Spotify where it's available alongside your other listening.\n\n## Quick Start\n\nPrompt your agent to install:\n\n```text\n\u003e Install Save to Spotify by running https://saveto.spotify.com/install.sh\n```\n\nInstalls the CLI and exposes the skill to Claude Code, Cursor, Codex, and any agent that reads `.agents/skills/`.\n\nOnce installed, invoke with `/save-to-spotify` (Claude Code) or `$save-to-spotify` (Codex), or just describe what you want in plain English.\n\n## Install\n\n### Curl-bash\n\nSame script the Quick Start prompt runs:\n\n```bash\ncurl -fsSL https://saveto.spotify.com/install.sh | bash\n```\n\nCommon options:\n\n```bash\n# Pin a specific version\ncurl -fsSL https://saveto.spotify.com/install.sh | bash -s -- --version 0.1.1\n\n# Custom install directory\ncurl -fsSL https://saveto.spotify.com/install.sh | bash -s -- --dir ~/.local/bin\n\n# Binary only, skip the agent skill\ncurl -fsSL https://saveto.spotify.com/install.sh | bash -s -- --no-skills\n```\n\n### Skills.sh\n\nInstall the agent skill to Claude Code, Cursor, Codex, and 50+ other agents:\n\n```bash\nnpx skills add spotify/save-to-spotify\n```\n\n### ClawHub / OpenClaw\n\nSave to Spotify is listed on ClawHub as [`@spotify/save-to-spotify`](https://clawhub.ai/spotify/save-to-spotify). Install it into your active OpenClaw workspace:\n\n```bash\nopenclaw skills install @spotify/save-to-spotify\n```\n\nThe ClawHub listing installs the agent skill. The skill uses the `save-to-spotify` CLI, so if the binary is not already on your `PATH`, run the curl-bash installer above.\n\n### Claude Code plugin marketplace\n\n```\n/plugin marketplace add spotify/save-to-spotify\n/plugin install save-to-spotify@save-to-spotify\n```\n\n### Manual\n\nIf you can't run the install script:\n\n1. Download `save-to-spotify-{os}-{arch}-v{version}.zip` and its matching `.sha256` from the [releases page](https://github.com/spotify/save-to-spotify/releases).\n2. Verify integrity:\n   ```bash\n   shasum -c save-to-spotify-darwin-arm64-v0.1.1.zip.sha256\n   ```\n3. Unzip, you get the binary plus a `skills/save-to-spotify/` tree.\n4. Move the binary to a directory on your `PATH` and `chmod +x` it.\n5. (Optional) Copy `skills/save-to-spotify/` into your agent's skill directory, e.g. `~/.claude/skills/save-to-spotify/` or `~/.cursor/skills/save-to-spotify/`.\n\n### Build from source\n\nRequires [Go](https://go.dev/dl/) 1.21+.\n\n```bash\ngo build -ldflags \"-X github.com/spotify/save-to-spotify/cmd.commit=$(git rev-parse --short HEAD)\" \\\n  -o save-to-spotify .\nsudo mv save-to-spotify /usr/local/bin/\n```\n\n## Authentication\n\nLog in once, the CLI stores your token and refreshes it automatically.\n\n```bash\n# Opens your browser to authorize (default)\nsave-to-spotify auth login\n\n# Headless mode, prints a URL to open on any device, then you paste back the redirect URL\n# Useful for SSH sessions and remote servers\nsave-to-spotify auth login --no-browser\n\n# Check if you're logged in\nsave-to-spotify auth status\n\n# Log out (removes stored credentials)\nsave-to-spotify auth logout\n```\n\nTokens are stored in `~/.config/save-to-spotify/token.json` (using `$XDG_CONFIG_HOME` if set). If you use DPoP-bound tokens (the default), the sibling `dpop_key.json` is also required. For CI and headless environments, see the [CI / Automation guide](docs/ci-automation.md).\n\n## Commands\n\n### upload\n\nThe primary command. Uploads a media file and creates an episode in one step. This is the main entrypoint for agents, a single command handles show creation, file upload, and episode metadata.\n\n```bash\nsave-to-spotify upload \u003cfile\u003e --title \u003ctitle\u003e [flags]\n```\n\n| Flag | Description |\n|---|---|\n| `--title` | Episode title (required) |\n| `--show-id` | Target show ID or URI |\n| `--new-show` | Create a new show with this title and save the file to it |\n| `--summary` | Episode description |\n| `--image` | Cover image file (`.jpg`/`.png`, max 1 MB) |\n| `--language` | Language code (default: `en`) |\n\nIf `--show-id` or `--new-show` is not specified, the CLI will use your most recently created show, or create a new one if none exists.\n\n```bash\n# Save an audio file to Spotify, uses your most recent show (or creates one automatically)\nsave-to-spotify upload ./recap.mp3 --title \"Monday Standup Recap\"\n\n# Save to a specific show\nsave-to-spotify upload ./lesson.mp3 --title \"Spanish Lesson 12\" --show-id spotify:show:abc123\n\n# Organize saved items into separate shows\nsave-to-spotify upload ./lecture.mp3 --title \"CS 101 — Lecture Notes Week 6\" --new-show \"Lecture Notes\"\n\n# With cover image and description\nsave-to-spotify upload ./briefing.mp3 \\\n  --title \"Morning Briefing\" \\\n  --summary \"Weather and calendar for today\" \\\n  --image ./cover.jpg\n```\n\n**Supported formats:** `.mp3`, `.m4a`, `.wav`, `.ogg`.\n\n### shows\n\nShows are containers for your saved content. You can use a single show for everything or create separate shows to organize by topic (e.g. \"Daily Briefings\", \"Language Practice\", \"Meeting Recaps\").\n\n```bash\n# List your shows\nsave-to-spotify shows\n\n# Create a show\nsave-to-spotify shows create --title \"Lecture Notes\" --summary \"Audio summaries of CS 101 lectures\"\n\n# Get show details\nsave-to-spotify shows get \u003cid\u003e\n\n# Delete a show and all its episodes\nsave-to-spotify shows delete \u003cid\u003e\n```\n\n`shows create` flags:\n\n| Flag | Description |\n|---|---|\n| `--title` | Show title (required) |\n| `--summary` | Show description (default: \"(no description)\") |\n| `--image` | Cover image file (`.jpg`/`.png`, max 1 MB) |\n| `--language` | Language code (default: `en`) |\n\n### episodes\n\nEach saved file becomes an episode within a show.\n\n```bash\n# List episodes (for your most recent show)\nsave-to-spotify episodes\n\n# List episodes for a specific show\nsave-to-spotify episodes --show-id spotify:show:abc123\n\n# Create an episode (more control than `upload`, same underlying operation)\nsave-to-spotify episodes create --title \"Sprint Review Notes\" --file ./review.mp3\n\n# Check if an episode is ready for playback\nsave-to-spotify episodes status \u003cepisode-id\u003e\n\n# Wait until an episode is ready (default timeout: 5m)\nsave-to-spotify episodes status \u003cepisode-id\u003e --wait\n\n# Wait with a custom readiness timeout\nsave-to-spotify episodes status \u003cepisode-id\u003e --wait 2m\n\n# Delete an episode\nsave-to-spotify episodes delete \u003cepisode-id\u003e\n```\n\n`episodes create` flags:\n\n| Flag | Description |\n|---|---|\n| `--title` | Episode title (required) |\n| `--file` | Media file path (required) |\n| `--show-id` | Target show ID or URI (default: most recent show) |\n| `--summary` | Episode description |\n| `--image` | Cover image file (`.jpg`/`.png`, max 1 MB) |\n| `--language` | Language code |\n\n### timeline\n\nAdd chapter markers and in-player companion content to saved episodes. A timeline can include chapters, images, external links, and Spotify-native references via `spotify_entity`. Prefer `spotify_entity` whenever the thing you want listeners to open already exists on Spotify, prefer full `spotify:...` URIs over bare IDs or `open.spotify.com` URLs, and note that a `link` and a `spotify_entity` can both appear in the same timeline when both destinations are useful.\n\n```bash\n# Get timeline items for an episode\nsave-to-spotify timeline get \u003cepisode-id\u003e\n\n# Set (replace all) timeline items from a JSON file\nsave-to-spotify timeline set --episode-id \u003cepisode-id\u003e --from-file timeline.json\n\n# Delete all timeline items\nsave-to-spotify timeline delete \u003cepisode-id\u003e\n```\n\nExample `timeline.json`:\n\n```json\n{\n  \"items\": [\n    { \"chapter\": { \"title\": \"Introduction\", \"start_time_ms\": 0 } },\n    { \"chapter\": { \"title\": \"Key Concepts\", \"start_time_ms\": 45000 } },\n    { \"spotify_entity\": { \"start_time_ms\": 60000, \"duration_ms\": 30000, \"uri\": \"spotify:track:abc123\" } },\n    { \"link\": { \"start_time_ms\": 95000, \"duration_ms\": 20000, \"url\": \"https://example.com/slides\" } },\n    { \"chapter\": { \"title\": \"Summary\", \"start_time_ms\": 120000 } }\n  ]\n}\n```\n\nTimeline rules:\n\n- `chapter`: optional, but if present there must be at least 2; the first must start at `0`.\n- `image`: requires a positive `duration_ms` and a local `.jpg`/`.png` file path or an `image_token`.\n- `link`: requires a positive `duration_ms` and an HTTP(S) URL.\n- `spotify_entity`: requires a full `spotify:...` URI; `duration_ms` is optional but must be positive when set.\n- Companion items (`image`, `link`, `spotify_entity`) must not overlap in time, but a `link` and a `spotify_entity` may share the same segment/chapter as long as their windows do not overlap.\n\n### list\n\nAlternative command for listing your content.\n\n```bash\n# List episodes for the most recent show\nsave-to-spotify list\n\n# List episodes for a specific show\nsave-to-spotify list episodes --show-id spotify:show:abc123\n\n# List all shows\nsave-to-spotify list shows\n```\n\n### Other commands\n\n| Command | Description |\n|---|---|\n| `update` | Check for and install CLI updates |\n| `token` | Print access token to stdout (for piping to `curl`, etc.) |\n| `version` | Print version and commit hash |\n\n## Global flags\n\n| Flag | Description |\n|---|---|\n| `--json` | Output results as JSON (for scripting and automation) |\n| `--timeout \u003cduration\u003e` | API request timeout (default: `30s`, e.g. `1m`, `90s`) |\n\n## Documentation\n\n- [Agent integration](docs/agent-integration.md) — JSON mode, typical workflow, error handling\n- [CI / Automation](docs/ci-automation.md) — GitHub Actions setup, headless auth, credential persistence\n\n## Environment variables\n\n| Variable | Purpose | Default |\n|---|---|---|\n| `SAVE_TO_SPOTIFY_AUTH_TOKEN` | Bearer token override (expires in ~1 hour, no auto-refresh — see [CI guide](docs/ci-automation.md)) | — |\n| `SAVE_TO_SPOTIFY_BACKEND_URL` | Override the backend API URL | `https://saveto.spotify.com` |\n| `SAVE_TO_SPOTIFY_TIMEOUT` | API request timeout (e.g. `30s`, `2m`) | `30s` |\n| `SAVE_TO_SPOTIFY_CLIENT_ID` | OAuth client ID override | built-in |\n| `SAVE_TO_SPOTIFY_NO_UPDATE_CHECK` | Disable passive update checks | off |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspotify%2Fsave-to-spotify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspotify%2Fsave-to-spotify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspotify%2Fsave-to-spotify/lists"}