Skip to main content

CLI and Python client for the CUB REST API (cub.rip)

Project description

cubctl

CLI and Python library for the CUB REST API (cub.rip).

Quick start

pip install cubctl
cubctl --help

Development install from this repo:

pip install -e ".[dev]"
cubctl --help
# or: python -m cubctl --help

The package lives under src/cubctl/. From the repo root, cubctl is available after pip install -e . (or PYTHONPATH=src python -m cubctl).

Concepts (AWS-style)

Term CLI flag Config Description
Account slot --account src|target account_src / account_target Saved API token + default profile ID (like AWS named profiles, fixed as src and target for migrations)
CUB profile --profile ID per-slot profile field User profile within an account (Pavel, DEVOPS, …). Many commands need an explicit profile ID

Credential chain (highest priority first):

  1. --account src|target (+ optional --profile override)
  2. --token (+ optional --profile)
  3. CUB_TOKEN / CUB_PROFILE environment variables
  4. Default slot: CUB_ACCOUNT env or account_src

Global flags (before or after the subcommand):

cubctl --account src --profile 311483 bookmarks all --type book
cubctl bookmarks all --account src --profile 311483 --type book

Install

pip install cubctl
pip install "cubctl[test]"   # optional: pytest for running tests

From source:

pip install -e ".[dev]"
cubctl --help

Authentication (device/add)

CUB uses device-based login — the same flow as Lampa:

  1. Open cub.rip/add while logged in to your CUB account
  2. Copy the 6-digit code shown on the page
  3. Exchange it for a token via POST device/add
cubctl device add 123456 --save   # saves to src account slot in config
cubctl auth 123456 --save         # alias; prefer accounts setup for src + target

For src + target account slots:

cubctl accounts setup   # reads accounts.env in repo root
cubctl accounts show

Credentials live in ~/.cub/config.json — account tokens, default slot, and saved profile names. Manage with cubctl config:

cubctl config show                              # accounts + profiles (no tokens)
cubctl config path
cubctl config set default-account src
cubctl config profile sync --account src        # fetch profile names from API → config
cubctl config profile list --account src
cubctl config profile set --account src --name Pavel --id 311483
cubctl config profile default --account src --name Pavel
cubctl bookmarks all --account src --profile Pavel   # name resolved from config

Example ~/.cub/config.json:

{
  "default_account": "src",
  "account_src": {
    "token": "...",
    "profile": "311483",
    "email": "user@example.com",
    "profiles": {
      "Pavel": "311483",
      "Kids": "311484"
    }
  },
  "account_target": {
    "token": "...",
    "profile": "796529",
    "profiles": { "Main": "796529" }
  }
}

The client sends these headers on every authenticated request:

Header Purpose
token API access token (required)
profile Profile ID (required for some)

Environment variables

Variable Description Default
CUB_TOKEN API token
CUB_PROFILE CUB profile ID
CUB_ACCOUNT Default account slot: src or target src when configured
CUB_CODE_SRC Device code for src slot (setup)
CUB_CODE_TARGET Device code for target slot (setup)
CUB_FROM_TOKEN Source token for migration
CUB_TO_TOKEN Target token for migration
CUB_BASE_URL API base URL https://cub.rip/api/
CUB_CONFIG_DIR Config directory ~/.cub

accounts.env is auto-loaded at startup when present (see accounts.env.example).

Public vs authenticated commands

These work without a token:

cubctl collections top-collectors
cubctl collections list --category new
cubctl collections roll
cubctl collections view 123
cubctl reactions get movie_539972
cubctl reactions add movie_539972 think
cubctl users find --email user@example.com

All other subcommands require --account src|target, --token, or accounts setup.

Credential resolution

Every authenticated subcommand accepts:

Flag Env Config
--account src|target CUB_ACCOUNT account_src / account_target
--token CUB_TOKEN — (explicit override only)
--profile CUB_PROFILE slot profile or profiles map

Order: --account → explicit --tokenaccount_src → error with setup hint.

Profiles

List and resolve CUB profile IDs by name:

cubctl profiles all --account src
cubctl profiles pick --account src --name Pavel
cubctl profiles pick --account target --name DEVOPS

Use the returned id with --profile or --from-profile / --to-profile.

Bookmarks

The API has documented filter types (book, history, like, wath) and internal types returned with --full 1 (viewed, scheduled, look, thrown, …).

# Category counts (matches Lampa UI totals)
cubctl bookmarks counts --account src --profile 311483

# List by type
cubctl bookmarks all --account src --profile 311483 --type history

# All internal types (~400 items)
cubctl bookmarks all --account src --profile 311483 --full 1

Premium

Timeline endpoints require CUB Premium: timeline/all, changelog, dump, update.

Backup (JSON v2)

Full profile snapshot including all bookmark internal types, timeline, and optional notifications.

cubctl backup create --account src --profile 311483
cubctl backup restore --account target --profile 796529 -i backup.json --dry-run
cubctl backup restore --account target --profile 796529 -i backup.json

Equivalent: migrate export / migrate import (same JSON format).

Account slots (src / target)

cp accounts.env.example accounts.env
# edit CUB_CODE_SRC, CUB_CODE_TARGET, optional CUB_ACCOUNT=src
cubctl accounts setup
cubctl bookmarks all --account src --type book
cubctl migrate run \
  --from src --from-profile 311483 \
  --to target --to-profile 796529 \
  --dry-run

Migration

Copy all bookmark types + timeline (+ optional notifications) between profiles or account slots.

Always specify profile IDs — saved slots store the main profile from login, not named profiles like Pavel.

# Preview
cubctl migrate run \
  --from src --from-profile 311483 \
  --to target --to-profile 796529 \
  --dry-run

# Run with progress
cubctl migrate run \
  --from src --from-profile 311483 \
  --to target --to-profile 796529 \
  --include bookmarks,timeline,notifications \
  --progress

# Export / import (offline)
cubctl migrate export --from src --from-profile 311483 -o pavel.json
cubctl migrate import --to target --to-profile 796529 -i pavel.json --progress
Flag Description
--from / --to Account slot: src or target
--from-profile / --to-profile CUB profile ID within each slot
--include bookmarks,timeline,notifications What to migrate
--merge skip Skip existing items (default)
--merge overwrite Overwrite timeline entries
--dry-run Counts only, no writes
--progress Print each import step to stderr
--quiet Compact JSON (export: summary only)
--delay SECS Pause between API writes (rate limiting)

Same account slot, two CUB profiles (one token):

cubctl migrate run --from-profile 311484 --to-profile 311483 --dry-run

Security notes

  • Tokens are stored in plain text in ~/.cub/config.json (local CLI tool).
  • users give --password passes the password on the command line (visible in shell history). Prefer env vars in scripts.

Tests

pip install -e ".[test]"
pytest tests/test_unit.py tests/test_migration.py tests/test_cli.py -m "not integration"
pytest tests -m integration   # live API; needs CUB_TEST_DEVICE_CODE

Project layout

lampa-cub-cli/
├── README.md
├── pyproject.toml
├── requirements.txt
├── accounts.env.example
├── tests/
└── src/cubctl/
    ├── cli.py           # command dispatch
    ├── cli_helpers.py   # auth resolution, progress, public commands
    ├── client.py
    ├── migration.py
    └── api_spec.json
pip install -e ".[dev]" && cubctl --help

Publish to PyPI

Recommended: Trusted Publisher (no long-lived token)

PyPI exchanges a short-lived token with GitHub via OIDC. You do not need PYPI_API_TOKEN in GitHub Secrets when this is configured.

1. PyPIAccount → Publishing (or project → Publishing after the first release)

Add a GitHub trusted publisher:

Field Value
Owner pavelpikta
Repository lampa-cub-cli
Workflow name publish.yml
Environment pypi (optional but matches this repo’s workflow)

For the first upload, you can add a pending publisher before the cubctl project exists on PyPI.

2. GitHub — repo Settings → Environments

Create environment pypi (optional protections: required reviewers, branch rules).

No repository secret is required for trusted publishing.

3. Release

git tag v1.0.0
git push origin v1.0.0
# GitHub → Releases → Draft new release from tag v1.0.0 → Publish

Or run Actions → publish → Run workflow manually.

The workflow uses pypa/gh-action-pypi-publish with id-token: write (see .github/workflows/publish.yml).

Alternative: API token + secret

If you prefer a classic token instead of trusted publishing:

  1. PyPI → Account settings → API tokens → create token (scope: entire account or project cubctl)
  2. GitHub → Settings → Secrets and variables → Actions → PYPI_API_TOKEN
  3. Replace the publish step in publish.yml with:
      - name: Publish to PyPI
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
        run: twine upload dist/*

Remove id-token: write if you use only the token method.

Manual upload (local)

pip install build twine
python -m build
twine check dist/*
twine upload dist/*
# Username: __token__  Password: pypi-Ag... (API token)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cubctl-1.0.0.tar.gz (42.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cubctl-1.0.0-py3-none-any.whl (36.0 kB view details)

Uploaded Python 3

File details

Details for the file cubctl-1.0.0.tar.gz.

File metadata

  • Download URL: cubctl-1.0.0.tar.gz
  • Upload date:
  • Size: 42.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cubctl-1.0.0.tar.gz
Algorithm Hash digest
SHA256 7aef3cdcce1c62077dc029d53d74500f88f1f97c3d5e08173622a6727ae8f7bc
MD5 28ccbe9f863d0d304e142e12126f2b09
BLAKE2b-256 11b2eb0ae98a8230b307e5a69cfb4ecb7cf7576fcecde19f5a5ec9ceb5edad9a

See more details on using hashes here.

Provenance

The following attestation bundles were made for cubctl-1.0.0.tar.gz:

Publisher: publish.yml on pavelpikta/cubctl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cubctl-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: cubctl-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 36.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cubctl-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 55280fb9e86773422153cbe6c9e55069a02c91d5e0b848cb54207fb98dac3dfa
MD5 7289260edf970778f1700d4c8bce0b51
BLAKE2b-256 cf7c985b245a5c7d0da91d1ecd20ffbeb167c4177cb3a83f8a6718a1dd5bad3a

See more details on using hashes here.

Provenance

The following attestation bundles were made for cubctl-1.0.0-py3-none-any.whl:

Publisher: publish.yml on pavelpikta/cubctl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page