Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

160 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Table of Contents generated automatically

Impartus CLI

Build Status License: MIT

A Go-based CLI and HTTP API server for downloading lecture videos from Impartus platforms. Features interactive mode for humans and deterministic JSON mode for automation and AI agents.

Features

  • Interactive CLI Mode - Guided download flow with course/lecture selection
  • Deterministic JSON Mode - Machine-readable output for automation and AI agent integration
  • HTTP API with WebSocket Events - REST API with real-time job progress updates
  • Multi-View Video Processing - Support for instructor/dual-view video streams
  • AES Encrypted Chunk Handling - Automatic decryption of Impartus video chunks
  • Pipeline Parallelization - Concurrent download + decrypt for faster throughput
  • Progress Tracking with ETA - Real-time progress bars with speed and time estimates
  • Rate Limiting - Configurable API and download rate limits
  • Slide Download Support - Download lecture slides alongside video content

Quick Start

Install

# Install from source
go install github.com/rabesss/impartus-cli@latest

# Or run the container package
docker run --rm ghcr.io/rabesss/impartus-cli:main --help

# Or download the latest release asset
gh release download --repo rabesss/impartus-cli --pattern 'impartus_*_linux_amd64.tar.gz'

# Or build from source
git clone https://github.com/rabesss/impartus-cli
cd impartus-cli
go build -o impartus .

Requirements

  • Go 1.25+ - Go toolchain for building (pinned in go.mod; Docker images may use a newer patch release)
  • FFmpeg - Required for video processing (must be in PATH)
  • mpv - Required for the play command (must be in PATH)
  • Impartus Account - Valid credentials for your institution's Impartus platform

Container usage

The --help command above is a quick image and entrypoint smoke test. For a real download, mount the configuration read-only and provide writable download and temporary directories:

mkdir -p downloads temp
docker run --rm \
  --volume "$PWD/config.json:/work/config.json:ro" \
  --volume "$PWD/downloads:/work/downloads" \
  --volume "$PWD/temp:/work/temp" \
  ghcr.io/rabesss/impartus-cli:main \
  download --subject 123 --session 456

The image runs as the non-root impartus user. Bind-mounted downloads and temp directories retain their host ownership and permissions, so they must be writable by that container user. API jobs are stored in /work/.jobs.json; the file is ephemeral when the container is removed unless /work is persisted.

Configuration

  1. Create a private configuration file:
make config-init

This copies the sample when config.json does not exist and sets owner-only permissions (0600). If the file already exists, the command only tightens its permissions and never overwrites your configuration. You can apply the same protection manually with chmod 600 config.json.

  1. Edit config.json with your credentials:
{
  "username": "your_impartus_email@example.com",
  "password": "your_impartus_password",
  "baseUrl": "https://a.impartus.com/api",
  "quality": "720",
  "views": "both",
  "downloadLocation": "./downloads"
}

Configuration Options

Field Type Required Default Description
username string Yes - Impartus username (email)
password string Yes - Impartus password
baseUrl string Yes - Impartus API base URL
quality string No "720" Video quality: 144, 450, 720
views string No "both" Views: left, right, both, first, second
downloadLocation string No "./downloads" Output directory
tempDirLocation string No "./temp" Temporary directory
slides bool No false Download slides alongside video
audioOnly bool No false Download audio only
audioFormat string No "mp3" Audio format: mp3, m4a, aac, opus
numWorkers int No 5 Concurrent lecture workers (1-50); active playlist downloads are bounded by per-lecture media workers to preserve the browser-observed burst envelope
rateLimit float No 100 Download rate limit (0.1-100 req/sec)
apiRateLimit float No 2 API rate limit (0.1-20 req/sec)
enablePipeline bool No false Enable concurrent download+decrypt
downloadWorkersPerLecture int No 12 Download workers per lecture (1-12)
decryptWorkersPerLecture int No 4 Decrypt workers per lecture (1-10)
httpTimeout string No "10m" Timeout for the shared upstream HTTP client, including login, API, playlist, and media requests (30s-60m)
enableJitter bool No true Add small random delays to API requests
skipNoAudio bool No false Skip lectures with no audio track
listenAddr string No "127.0.0.1" API server bind address (loopback only unless allowRemoteAccess is set)
allowRemoteAccess bool No false Permit a non-loopback listenAddr (e.g. 0.0.0.0); required to expose the API on the network
progressTracking object No see below Progress bar tracking configuration

Progress Tracking Options

Field Type Default Description
enabled bool false Enable all progress bars in human-readable mode; JSON mode remains quiet
showSpeed bool false Include download speed in the aggregate progress status
showETA bool false Include estimated time remaining in the aggregate progress status
updateInterval string "2s" Speed-sampling interval (500ms-10s)
speedWindowSize int 10 Number of samples used for the speed moving average (3-30)

Environment Variables

Only the settings listed below have environment-variable overrides. Settings absent from this table must be configured in JSON.

Environment variable Config field Notes
IMPARTUS_USERNAME username Required unless supplied in JSON
IMPARTUS_PASSWORD password Required unless supplied in JSON
IMPARTUS_BASE_URL baseUrl Required unless supplied in JSON
IMPARTUS_QUALITY quality 144, 450, or 720
IMPARTUS_VIEWS views left, right, both, first, or second
IMPARTUS_DOWNLOAD_LOCATION downloadLocation Output directory
IMPARTUS_TEMP_DIR tempDirLocation Temporary directory
IMPARTUS_TEMP_DIR_LOCATION tempDirLocation Compatibility alias for the shorter temporary-directory variable
IMPARTUS_AUDIO_FORMAT audioFormat mp3, m4a, aac, or opus
IMPARTUS_HTTP_TIMEOUT httpTimeout Go duration between 30s and 60m
IMPARTUS_LISTEN_ADDR listenAddr Non-loopback values also require remote-access opt-in
IMPARTUS_AUDIO_ONLY audioOnly Boolean
IMPARTUS_SLIDES slides Boolean
IMPARTUS_SKIP_NO_AUDIO skipNoAudio Boolean
IMPARTUS_ALLOW_REMOTE_ACCESS allowRemoteAccess Boolean
IMPARTUS_ENABLE_JITTER enableJitter Boolean
IMPARTUS_PROGRESS_TRACKING_ENABLED progressTracking.enabled Boolean; controls all progress bars
IMPARTUS_NUM_WORKERS numWorkers Integer from 1-50
IMPARTUS_RATE_LIMIT rateLimit Number from 0.1-100
IMPARTUS_API_RATE_LIMIT apiRateLimit Number from 0.1-20

Validation Rules

  • username and password are required
  • baseUrl must be a valid URL
  • quality must be one of: 144, 450, 720
  • views must be one of: left, right, both, first, second
  • numWorkers must be between 1-50
  • rateLimit must be between 0.1-100
  • httpTimeout must be between 30s-60m

CLI Usage

Interactive Mode

Run without arguments for guided download:

./impartus

This launches an interactive workflow:

  1. Log in with configured credentials
  2. Select course from list
  3. Select session/lecture range
  4. Download with progress tracking

Deterministic JSON Mode

Pass --json for machine-readable output:

# Get capability metadata
./impartus --json

# List courses
./impartus courses --json

# List lectures
./impartus lectures -s 123 -S 456 --json

Response envelope:

{
  "success": true,
  "data": {},
  "error": null,
  "meta": {
    "command": "courses",
    "mode": "json"
  }
}

Successful JSON commands write exactly one response envelope to stdout. They do not write progress bars or warning text, and successful downloads leave stderr empty. Failed JSON commands exit non-zero and write exactly one error envelope to stderr while leaving stdout empty; in that envelope, success is false, data is null, and error.message contains the error text.

For JSON downloads, lectureCount is the number of lectures completed. outputPaths contains the files produced, so one completed lecture can add multiple paths when multiple views or output forms are requested.

Command Reference

Command Description
impartus Interactive mode (guided download)
impartus --json Capability metadata
impartus help Show usage information
impartus version Show version and build date
impartus courses List available courses
impartus lectures -s ID -S ID List lectures for subject/session
impartus download [flags] Download lectures
impartus play [flags] Play lectures in mpv
impartus serve [--port PORT] Start HTTP API server

Download / Play Flags

./impartus download --subject 123 --session 456 [flags]
./impartus play --subject 123 --session 456 [flags]
Flag Short Description Applicable To
--subject -s Subject ID (required) Both
--session -S Session ID (required) Both
--start Start lecture index (1-based) Both
--end End lecture index (1-based, inclusive) Both
--lecture -l Specific lecture index (shortcut for start & end) Play Only
--quality Quality: 144, 450, 720 Both
--views Views: left, right, both, first, second Both
--audio-only Audio-only mode Download Only
--format Audio format: mp3, m4a, aac, opus Download Only
--output -o Output directory Download Only
--json JSON output (non-blocking) Download Only

Examples:

# Download lectures 1-5 from course
./impartus download -s 123 -S 456 --start 1 --end 5

# Download in 720p quality
./impartus download -s 123 -S 456 --quality 720

# Download audio only
./impartus download -s 123 -S 456 --audio-only --format mp3

# Download to custom directory
./impartus download -s 123 -S 456 -o /path/to/output

# Play lectures 1-5 from course
./impartus play -s 123 -S 456 --start 1 --end 5

# Play a specific lecture
./impartus play -s 123 -S 456 --lecture 3

API Server

Start the HTTP API server with job persistence:

# Jobs are persisted to .jobs.json and survive server restarts
./impartus serve

Job Persistence: Jobs are automatically saved to .jobs.json. Running/pending jobs at shutdown are restored as failed (non-resumable). Completed/failed/canceled jobs are restored with their preserved state.

# Default port 8080
./impartus serve

# Custom port
./impartus serve --port 9090

# JSON metadata (non-blocking)
./impartus serve --json

API Usage

Authentication

# Login
curl -X POST http://localhost:8080/api/v1/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"username":"your_user", "password":"your_pass"}'

Response:

{
  "success": true,
  "data": {
    "token": "eyJ...",
    "expires": "2025-02-12T12:34:56Z"
  }
}

Use the token for authenticated requests:

curl -H "Authorization: Bearer <token>" http://localhost:8080/api/v1/courses

Endpoints

Method Endpoint Auth Description
GET /api/v1/health/live No Process liveness check
GET /api/v1/health/ready No Cached dependency readiness check
GET /api/v1/health No Compatibility alias for readiness
POST /api/v1/auth/login No Authenticate
GET /api/v1/courses Yes List courses
GET /api/v1/lectures Yes List lectures
POST /api/v1/jobs Yes Create download job
GET /api/v1/jobs Yes List all jobs
GET /api/v1/jobs/{id} Yes Get job status
DELETE /api/v1/jobs/{id} Yes Cancel job
GET /api/v1/ws Yes WebSocket events

Health Endpoint

# Use this for process or container liveness probes (no dependency checks)
curl http://localhost:8080/api/v1/health/live

# Use this for dependency readiness
curl http://localhost:8080/api/v1/health/ready

/api/v1/health/live returns the standard envelope with data.status set to ok and performs no configuration, network, token-cache, filesystem, or executable checks.

/api/v1/health/ready returns a structured {success, data, error, meta} envelope with sub-checks for config, upstream, and FFmpeg status. /api/v1/health remains a compatibility alias with the same readiness response:

{
  "success": true,
  "data": {
    "status": "ok",
    "config": {
      "status": "ok"
    },
    "upstream": {
      "status": "reachable"
    },
    "ffmpeg": {
      "status": "available"
    }
  },
  "error": null,
  "meta": {
    "command": "health",
    "mode": "api"
  }
}

Status values:

  • config.status: ok (all fields set) or misconfigured (missing fields)
  • upstream.status: reachable (server responds), unreachable (TCP/HTTP fails), or not_configured (no baseUrl)
  • ffmpeg.status: available (in PATH) or not_found
  • Any sub-check may report unknown if readiness probing fails internally; inspect server logs for details
  • Overall status: ok (all sub-checks pass) or degraded (one or more sub-checks fail)

The unauthenticated health response deliberately exposes only aggregate configuration status; it does not reveal which credential fields are present. Readiness results, including degraded results, are cached for 15 seconds and may be that old. Readiness endpoints retain HTTP 200 when degraded, so callers must inspect data.status rather than relying on the HTTP status alone.

Create Download Job

Idempotency Key Support: Pass an optional idempotencyKey field to prevent duplicate job creation on network retries. If a job with the same key already exists, returns the existing job with HTTP 409 Conflict.

curl -X POST http://localhost:8080/api/v1/jobs \
  -H "Authorization: Bearer <token>" \
  -H 'Content-Type: application/json' \
  -d '{
    "subjectId": 123,
    "sessionId": 456,
    "startIndex": 1,
    "endIndex": 5,
    "idempotencyKey": "unique-identifier-here",
    "jobConfig": {
      "quality": "720",
      "views": "both",
      "enablePipeline": true,
      "numWorkers": 6
    }
  }'

Note: API uses 1-based indexing for startIndex and endIndex (inclusive), matching CLI --start and --end.

WebSocket Connection

Connect to receive real-time job updates:

import WebSocket from 'ws';

const ws = new WebSocket('ws://localhost:8080/api/v1/ws', {
  headers: {
    Authorization: `Bearer ${token}`
  }
});

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log(`Event: ${data.type}`, data);
};

WebSocket Events

Event Description
job.started Job began execution
job.progress Progress update (includes phase and percentage)
job.completed Job finished successfully
job.failed Job failed with error
job.cancelled Job was cancelled

See docs/websocket-events.md for complete event schemas.

WebSocket events are live notifications, not a durable event stream. A client that stops reading may be disconnected when its bounded outbound queue fills. Reconnect and query GET /api/v1/jobs/{id} to recover the current job state; events that occurred while disconnected are not replayed.

Development

Build & Test

# Build
make build

# Run tests
make test

# Run linter
make lint

# Run pre-commit hooks
make pre-commit

Makefile Targets

Target Description
make build Build the impartus binary
make test Run tests with coverage
make lint Run golangci-lint
make pre-commit-install Install pre-commit hooks
make pre-commit Run pre-commit on all files
make clean Clean build artifacts
make install Install to $GOPATH/bin
make run-cli Run CLI interactive mode
make run-api Start API server on port 8080
make docs Generate docs table of contents
make docs-toc Generate documentation table of contents
make security Run all security scans (gitleaks, gosec, trivy, govulncheck)
make security-gitleaks Run secret scanning
make security-gosec Run Go security analysis
make security-trivy Run vulnerability scanning
make security-govulncheck Run Go vulnerability check

Install development tools:

# Install golangci-lint
curl -sSfL https://raw.githubusercontent.com/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin

# Install pre-commit
pip install pre-commit
pre-commit install

Running Tests

# All tests
go test ./...

# With coverage
go test ./... -cover -coverprofile=coverage.out
go tool cover -func=coverage.out

# Verbose
go test ./... -v

Architecture

This project is CLI-first, API-secondary: the CLI is the primary execution path, and the API is started from impartus serve when needed.

Package Structure

impartus/
├── main.go                 # Root entrypoint
├── cmd/impartus/main.go    # Module-style entrypoint
├── internal/
│   ├── cli/                 # Command routing and implementations
│   ├── config/              # Configuration parsing and validation
│   ├── client/              # Impartus API client, auth, HTTP helpers
│   ├── downloader/          # Playlist parsing, chunk download/decrypt, ffmpeg
│   └── server/              # HTTP API, auth middleware, jobs, WebSocket
├── docs/                    # Documentation
└── config.json              # User configuration

Key Components

  • internal/cli - CLI command routing and interactive/deterministic modes
  • internal/config - Configuration loading, defaults, and validation
  • internal/client - Impartus API HTTP client with authentication
  • internal/downloader - Video pipeline: playlist parsing, chunk download, AES decryption, FFmpeg join
  • internal/server - HTTP API server with bearer-token auth, background jobs, and WebSocket broadcasting

For detailed flow diagrams, see docs/architecture.md.

Contributing

See CONTRIBUTING.md for local setup, PR guidelines, and code style expectations.

Security-sensitive changes are described in SECURITY.md.

License

MIT License - see LICENSE for details.

Acknowledgments

Dependencies

Documentation

About

cli to interact w impartus, download media for agent ingestion

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages