onair 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- onair-1.0.1/.cursor/rules/global.mdc +64 -0
- onair-1.0.1/.cursor/rules/markdown.mdc +25 -0
- onair-1.0.1/.github/workflows/check-tag.yml +50 -0
- onair-1.0.1/.github/workflows/publish.yml +59 -0
- onair-1.0.1/.github/workflows/quality-checks.yml +40 -0
- onair-1.0.1/.github/workflows/version-check.yml +61 -0
- onair-1.0.1/.gitignore +20 -0
- onair-1.0.1/.mdformat.toml +3 -0
- onair-1.0.1/.pre-commit-config.yaml +63 -0
- onair-1.0.1/AGENTS.md +13 -0
- onair-1.0.1/CONTRIBUTING.md +21 -0
- onair-1.0.1/LICENSE +21 -0
- onair-1.0.1/PKG-INFO +89 -0
- onair-1.0.1/README.md +69 -0
- onair-1.0.1/pyproject.toml +91 -0
- onair-1.0.1/src/onair/__init__.py +0 -0
- onair-1.0.1/src/onair/__main__.py +4 -0
- onair-1.0.1/src/onair/app.py +122 -0
- onair-1.0.1/src/onair/client/__init__.py +0 -0
- onair-1.0.1/src/onair/client/client.py +313 -0
- onair-1.0.1/src/onair/commands/__init__.py +48 -0
- onair-1.0.1/src/onair/commands/base.py +37 -0
- onair-1.0.1/src/onair/commands/countries.py +75 -0
- onair-1.0.1/src/onair/commands/genres.py +57 -0
- onair-1.0.1/src/onair/commands/help.py +35 -0
- onair-1.0.1/src/onair/commands/info.py +61 -0
- onair-1.0.1/src/onair/commands/mute.py +31 -0
- onair-1.0.1/src/onair/commands/next.py +38 -0
- onair-1.0.1/src/onair/commands/pause.py +21 -0
- onair-1.0.1/src/onair/commands/play.py +117 -0
- onair-1.0.1/src/onair/commands/previous.py +50 -0
- onair-1.0.1/src/onair/commands/quit.py +58 -0
- onair-1.0.1/src/onair/commands/resume.py +22 -0
- onair-1.0.1/src/onair/commands/stop.py +19 -0
- onair-1.0.1/src/onair/commands/unmute.py +31 -0
- onair-1.0.1/src/onair/commands/volume.py +70 -0
- onair-1.0.1/src/onair/player/__init__.py +0 -0
- onair-1.0.1/src/onair/player/player.py +59 -0
- onair-1.0.1/src/onair/utils/__init__.py +0 -0
- onair-1.0.1/src/onair/utils/colorize.py +56 -0
- onair-1.0.1/src/onair/utils/listing.py +55 -0
- onair-1.0.1/tests/mock_client.py +37 -0
- onair-1.0.1/tests/test_client.py +189 -0
- onair-1.0.1/tests/test_commands.py +366 -0
- onair-1.0.1/tests/test_player.py +40 -0
- onair-1.0.1/tests/test_utils.py +22 -0
- onair-1.0.1/uv.lock +738 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Coding standards for every project generated from cookiecutter-python-seed
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Generated project standards
|
|
7
|
+
|
|
8
|
+
This is a Python project generated from cookiecutter-python-seed. Treat `pyproject.toml` as the source of truth for toolchain, Python version, and dependencies. Minimum Python version is 3.12. Use uv to lock, sync, build, and bump versions.
|
|
9
|
+
|
|
10
|
+
You are a lazy senior developer. Lazy means efficient, not careless. The best code is the code never written.
|
|
11
|
+
|
|
12
|
+
## Before writing code
|
|
13
|
+
|
|
14
|
+
Read the task and the code it touches, trace the real flow end to end, then stop at the first rung that holds:
|
|
15
|
+
|
|
16
|
+
1. Does this need to be built at all? (YAGNI)
|
|
17
|
+
2. Does it already exist in this codebase? Reuse it.
|
|
18
|
+
3. Does the standard library already do this? Use it.
|
|
19
|
+
4. Does an already-declared dependency solve it? Use it.
|
|
20
|
+
5. Can this be one boring line? Make it one line.
|
|
21
|
+
6. Only then: write the minimum code that works.
|
|
22
|
+
|
|
23
|
+
Bug fix = root cause, not symptom. Grep every caller of the function you touch and fix the shared function once.
|
|
24
|
+
|
|
25
|
+
## Toolchain
|
|
26
|
+
|
|
27
|
+
- Match existing layout: `src/` for packages, `tests/` for tests, application entry points as already configured.
|
|
28
|
+
- Do not add a dependency unless it is declared in `pyproject.toml` (or the project's lockfile). Prefer stdlib over a new package.
|
|
29
|
+
- Style is enforced by Ruff. Follow `pyproject.toml`; the points below are the ones to apply consistently even when Ruff cannot.
|
|
30
|
+
- After editing Python files, run `poe format`.
|
|
31
|
+
- After editing Markdown files, run `poe format_docs`.
|
|
32
|
+
|
|
33
|
+
## Comments and docs
|
|
34
|
+
|
|
35
|
+
- No docstrings except on base/abstract classes and methods (the contract for implementors) and on complex functions where extra explanation genuinely helps.
|
|
36
|
+
- No unnecessary comments. Code should be self-explanatory. If a comment is needed, explain why, not what.
|
|
37
|
+
- No section-divider comments inside classes or functions. Group related methods by proximity. Dividers are allowed only in test classes.
|
|
38
|
+
|
|
39
|
+
## Language
|
|
40
|
+
|
|
41
|
+
- Type-hint every function and method. Do not nest annotations so deeply that they hurt readability.
|
|
42
|
+
- No unnecessary imports.
|
|
43
|
+
- Use f-strings for all string formatting.
|
|
44
|
+
- Avoid unnecessary `Path` wrappers; join with `/` on `Path` objects.
|
|
45
|
+
- ASCII only in identifiers, comments, and docs. No emojis. Non-ASCII letters are allowed only when the content is actually in another language (e.g. Polish, Russian).
|
|
46
|
+
|
|
47
|
+
## Quality
|
|
48
|
+
|
|
49
|
+
- Use `poe format` / `poe format_docs` instead of hand-formatting style.
|
|
50
|
+
- Deletion over addition. Boring over clever. Fewest files possible. Shortest working diff wins, after you understand the problem.
|
|
51
|
+
- No abstractions, boilerplate, or dependencies that weren't requested.
|
|
52
|
+
- Question complex requests: "Do you actually need X, or does Y cover it?"
|
|
53
|
+
- When two stdlib approaches are the same size, pick the edge-case-correct one.
|
|
54
|
+
- Mark deliberate simplifications that cut a real corner with a known ceiling (global lock, O(n^2) scan, naive heuristic) with a `ponytail:` comment naming the ceiling and upgrade path.
|
|
55
|
+
- Non-trivial logic leaves one runnable check: the smallest test that fails if the logic breaks. Trivial one-liners need no new test. Run the project's test command before claiming work is done.
|
|
56
|
+
- Do not commit secrets, `.env` files, or local virtualenvs.
|
|
57
|
+
|
|
58
|
+
Not lazy about: understanding the problem, input validation at trust boundaries, error handling that prevents data loss, security, anything explicitly requested.
|
|
59
|
+
|
|
60
|
+
## Agents
|
|
61
|
+
|
|
62
|
+
- Keep this file for conventions that should always apply.
|
|
63
|
+
- Put path-specific Cursor rules in additional `.mdc` files in this directory.
|
|
64
|
+
- Keep `AGENTS.md` as a short index that points here.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Markdown formatting for README, docs, and other .md files
|
|
3
|
+
globs: "**/*.md"
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Markdown
|
|
8
|
+
|
|
9
|
+
ASCII only. No emojis, smart quotes, or non-English letters.
|
|
10
|
+
|
|
11
|
+
Use fenced code blocks with a language tag when the snippet has a language:
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
Path("data") / "out.csv"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Do not leave unlabeled fences for Python, TOML, shell, or JSON. Plain fences are fine for output or prose examples with no language.
|
|
20
|
+
|
|
21
|
+
Keep heading levels, lists, and tables consistent within a file: one heading style, one list marker (`-`), one table alignment. Do not mix numbered and bulleted lists for the same kind of items.
|
|
22
|
+
|
|
23
|
+
Skip extra bold, italics, and emphasis. Highlight a term only when it would otherwise be missed.
|
|
24
|
+
|
|
25
|
+
Write short, plain sentences. If a technical term is necessary, introduce it in the same sentence.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: "Check Tag"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
inputs:
|
|
6
|
+
tag:
|
|
7
|
+
description: Version tag like v1.2.3
|
|
8
|
+
required: true
|
|
9
|
+
type: string
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
check-tag:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
ref: refs/tags/${{ inputs.tag }}
|
|
22
|
+
fetch-tags: true
|
|
23
|
+
fetch-depth: 0
|
|
24
|
+
|
|
25
|
+
- name: Check that tag is on main
|
|
26
|
+
env:
|
|
27
|
+
TAG: ${{ inputs.tag }}
|
|
28
|
+
run: |
|
|
29
|
+
git fetch origin refs/heads/main:refs/remotes/origin/main --force
|
|
30
|
+
if ! git merge-base --is-ancestor HEAD refs/remotes/origin/main; then
|
|
31
|
+
echo "tag $TAG is not on main"
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
- name: Set up uv
|
|
36
|
+
uses: astral-sh/setup-uv@v7
|
|
37
|
+
with:
|
|
38
|
+
python-version: '3.12'
|
|
39
|
+
enable-cache: false
|
|
40
|
+
|
|
41
|
+
- name: Ensure tag matches version in pyproject.toml
|
|
42
|
+
env:
|
|
43
|
+
TAG: ${{ inputs.tag }}
|
|
44
|
+
run: |
|
|
45
|
+
version=$(uv version --short)
|
|
46
|
+
tag_version="${TAG#v}"
|
|
47
|
+
if [ "$version" != "$tag_version" ]; then
|
|
48
|
+
echo "version in pyproject.toml ($version) does not match tag ($TAG)"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: "Publish"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*.*.*'
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
check-tag:
|
|
13
|
+
uses: ./.github/workflows/check-tag.yml
|
|
14
|
+
with:
|
|
15
|
+
tag: ${{ github.ref_name }}
|
|
16
|
+
|
|
17
|
+
build:
|
|
18
|
+
needs: check-tag
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- name: Checkout
|
|
22
|
+
uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- name: Set up uv
|
|
25
|
+
uses: astral-sh/setup-uv@v7
|
|
26
|
+
with:
|
|
27
|
+
python-version: '3.12'
|
|
28
|
+
|
|
29
|
+
- name: Build
|
|
30
|
+
run: uv build
|
|
31
|
+
|
|
32
|
+
- name: Upload artifact
|
|
33
|
+
uses: actions/upload-artifact@v4
|
|
34
|
+
with:
|
|
35
|
+
name: dist
|
|
36
|
+
path: dist/
|
|
37
|
+
|
|
38
|
+
publish:
|
|
39
|
+
needs: build
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
environment:
|
|
42
|
+
name: pypi
|
|
43
|
+
url: https://pypi.org/p/onair
|
|
44
|
+
permissions:
|
|
45
|
+
id-token: write
|
|
46
|
+
steps:
|
|
47
|
+
- name: Download artifact
|
|
48
|
+
uses: actions/download-artifact@v4
|
|
49
|
+
with:
|
|
50
|
+
name: dist
|
|
51
|
+
path: dist/
|
|
52
|
+
|
|
53
|
+
- name: Set up uv
|
|
54
|
+
uses: astral-sh/setup-uv@v7
|
|
55
|
+
with:
|
|
56
|
+
enable-cache: false
|
|
57
|
+
|
|
58
|
+
- name: Publish
|
|
59
|
+
run: uv publish --trusted-publishing always
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: "Quality Checks"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
types: [opened, synchronize, reopened]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
quality-checks:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up uv
|
|
20
|
+
uses: astral-sh/setup-uv@v7
|
|
21
|
+
with:
|
|
22
|
+
python-version: '3.12'
|
|
23
|
+
|
|
24
|
+
- name: Lock dependencies
|
|
25
|
+
run: uv lock --check
|
|
26
|
+
|
|
27
|
+
- name: Sync dependencies
|
|
28
|
+
run: uv sync --locked
|
|
29
|
+
|
|
30
|
+
- name: Check code formatting
|
|
31
|
+
run: uv run ruff format --check .
|
|
32
|
+
|
|
33
|
+
- name: Check code linting
|
|
34
|
+
run: uv run ruff check .
|
|
35
|
+
|
|
36
|
+
- name: Check Markdown formatting
|
|
37
|
+
run: find . -name '*.md' ! -path './.venv/*' ! -path './.git/*' -print0 | xargs -0 -r uv run mdformat --check
|
|
38
|
+
|
|
39
|
+
- name: Run tests
|
|
40
|
+
run: uv run pytest
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: "Version Check"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [main]
|
|
6
|
+
types: [opened, synchronize, reopened]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
version-check:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
name: Ensure version bumped
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
|
+
with:
|
|
19
|
+
fetch-depth: 0
|
|
20
|
+
|
|
21
|
+
- name: Set up uv
|
|
22
|
+
uses: astral-sh/setup-uv@v7
|
|
23
|
+
with:
|
|
24
|
+
python-version: '3.12'
|
|
25
|
+
enable-cache: false
|
|
26
|
+
|
|
27
|
+
- name: Determine PR version
|
|
28
|
+
id: get-pr-version
|
|
29
|
+
run: echo "version=$(uv version --short)" >> "$GITHUB_OUTPUT"
|
|
30
|
+
|
|
31
|
+
- name: Determine main version
|
|
32
|
+
id: get-main-version
|
|
33
|
+
run: |
|
|
34
|
+
git fetch origin refs/heads/main:refs/remotes/origin/main --depth=1
|
|
35
|
+
git checkout -B main origin/main
|
|
36
|
+
main_version=$(uv version --short)
|
|
37
|
+
echo "Main version: $main_version"
|
|
38
|
+
echo "version=$main_version" >> "$GITHUB_OUTPUT"
|
|
39
|
+
|
|
40
|
+
- name: Compare versions
|
|
41
|
+
run: |
|
|
42
|
+
pr_version="${{ steps.get-pr-version.outputs.version }}"
|
|
43
|
+
main_version="${{ steps.get-main-version.outputs.version }}"
|
|
44
|
+
|
|
45
|
+
if [ -z "$pr_version" ] || [ -z "$main_version" ]; then
|
|
46
|
+
echo "Version is not set"
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
if [ "$pr_version" = "$main_version" ]; then
|
|
51
|
+
echo "Version unchanged ($pr_version). Please bump the version (e.g. poe patch)"
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
highest_version=$(echo -e "$pr_version\n$main_version" | sort -V | tail -n1)
|
|
56
|
+
if [ "$highest_version" != "$pr_version" ]; then
|
|
57
|
+
echo "Version $highest_version is higher than PR version $pr_version. Please bump the version (e.g. poe patch)"
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
echo "Version $pr_version is valid"
|
onair-1.0.1/.gitignore
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
minimum_pre_commit_version: '3.2.0'
|
|
2
|
+
|
|
3
|
+
default_install_hook_types:
|
|
4
|
+
- pre-push
|
|
5
|
+
- post-checkout
|
|
6
|
+
- post-merge
|
|
7
|
+
|
|
8
|
+
repos:
|
|
9
|
+
- repo: local
|
|
10
|
+
hooks:
|
|
11
|
+
- id: uv-lock-check
|
|
12
|
+
name: uv lock --check
|
|
13
|
+
description: check that uv.lock is consistent with pyproject.toml
|
|
14
|
+
entry: uv lock --check
|
|
15
|
+
language: system
|
|
16
|
+
pass_filenames: false
|
|
17
|
+
files: '^(pyproject\.toml|uv\.lock)$'
|
|
18
|
+
stages: [pre-push]
|
|
19
|
+
|
|
20
|
+
- id: uv-lock-check-after-git
|
|
21
|
+
name: uv lock --check
|
|
22
|
+
description: check that uv.lock is consistent with pyproject.toml
|
|
23
|
+
entry: uv lock --check
|
|
24
|
+
language: system
|
|
25
|
+
pass_filenames: false
|
|
26
|
+
always_run: true
|
|
27
|
+
stages: [post-checkout, post-merge]
|
|
28
|
+
|
|
29
|
+
- id: uv-sync
|
|
30
|
+
name: uv sync
|
|
31
|
+
description: sync dependencies
|
|
32
|
+
|
|
33
|
+
entry: uv sync --no-active --locked
|
|
34
|
+
|
|
35
|
+
language: system
|
|
36
|
+
always_run: true
|
|
37
|
+
pass_filenames: false
|
|
38
|
+
stages: [post-checkout, post-merge]
|
|
39
|
+
verbose: true
|
|
40
|
+
|
|
41
|
+
- id: ruff-check
|
|
42
|
+
name: ruff check
|
|
43
|
+
description: check for style issues
|
|
44
|
+
entry: uv run ruff check --force-exclude
|
|
45
|
+
language: system
|
|
46
|
+
pass_filenames: false
|
|
47
|
+
stages: [pre-push]
|
|
48
|
+
|
|
49
|
+
- id: ruff-format
|
|
50
|
+
name: ruff format
|
|
51
|
+
description: check that files are formatted
|
|
52
|
+
entry: uv run ruff format --check --force-exclude
|
|
53
|
+
language: system
|
|
54
|
+
pass_filenames: false
|
|
55
|
+
stages: [pre-push]
|
|
56
|
+
|
|
57
|
+
- id: md-format
|
|
58
|
+
name: md format
|
|
59
|
+
description: format markdown files
|
|
60
|
+
entry: uv run mdformat --check
|
|
61
|
+
language: system
|
|
62
|
+
files: '\.md$'
|
|
63
|
+
stages: [pre-push]
|
onair-1.0.1/AGENTS.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Agent instructions
|
|
2
|
+
|
|
3
|
+
This project was generated from cookiecutter-python-seed.
|
|
4
|
+
|
|
5
|
+
## Tooling
|
|
6
|
+
|
|
7
|
+
- All AI IDEs: follow this file.
|
|
8
|
+
- Cursor: project rules live in [`.cursor/rules/`](.cursor/rules/). This file is the index; do not duplicate those rules here.
|
|
9
|
+
|
|
10
|
+
## Standards
|
|
11
|
+
|
|
12
|
+
- Always-on: `.cursor/rules/global.mdc`
|
|
13
|
+
- Markdown (`.md` files): `.cursor/rules/markdown.mdc`
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
```shell
|
|
4
|
+
uv sync
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
Commit `uv.lock`. `poe hooks` installs git hooks (pre-push, post-checkout, post-merge).
|
|
8
|
+
|
|
9
|
+
```shell
|
|
10
|
+
poe check
|
|
11
|
+
poe check_docs
|
|
12
|
+
poe test
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`poe format` and `poe format_docs` apply the same tools in write mode.
|
|
16
|
+
|
|
17
|
+
## Release
|
|
18
|
+
|
|
19
|
+
Bump in the PR (`poe patch` / `minor` / `major`). CI fails if `[project].version` is not higher than on `main`.
|
|
20
|
+
|
|
21
|
+
After merge, tag `vX.Y.Z` on `main` (must match the project version) and push the tag. GitHub Actions publishes the sdist and wheel to PyPI using trusted publishing. Register this repository as a trusted publisher on PyPI before the first release.
|
onair-1.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Roman Kaczanowski
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
onair-1.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: onair
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Interactive internet radio for the terminal
|
|
5
|
+
Project-URL: Homepage, https://github.com/roman-kaczanowski/onair
|
|
6
|
+
Project-URL: Repository, https://github.com/roman-kaczanowski/onair
|
|
7
|
+
Project-URL: Issues, https://github.com/roman-kaczanowski/onair/issues
|
|
8
|
+
Author-email: Roman Kaczanowski <roman.kaczanowski.pl@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Python: >=3.12
|
|
16
|
+
Requires-Dist: prompt-toolkit
|
|
17
|
+
Requires-Dist: python-vlc
|
|
18
|
+
Requires-Dist: requests
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# onair
|
|
22
|
+
|
|
23
|
+
[](https://github.com/roman-kaczanowski/onair/actions/workflows/quality-checks.yml) [](https://pypi.org/project/onair/) [](https://docs.python.org/3/) [](LICENSE)
|
|
24
|
+
|
|
25
|
+
Turn your terminal into an internet radio. onair is a small interactive shell for finding and playing stations by genre or country.
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
- Browse popular genres and countries.
|
|
30
|
+
- Jump between stations and return to recently played ones.
|
|
31
|
+
- Pause, resume, mute, and adjust volume without leaving the prompt.
|
|
32
|
+
- Use tab completion, command history, and short aliases.
|
|
33
|
+
- Discover stations through [Radio Browser](https://www.radio-browser.info/) without an API key.
|
|
34
|
+
|
|
35
|
+
## Requirements
|
|
36
|
+
|
|
37
|
+
- Python 3.12 or newer.
|
|
38
|
+
- [VLC](https://www.videolan.org/vlc/) installed on your system. The `python-vlc` binding is installed with onair, but playback still requires the VLC application and its native library.
|
|
39
|
+
|
|
40
|
+
## Quick start
|
|
41
|
+
|
|
42
|
+
Install the release from PyPI:
|
|
43
|
+
|
|
44
|
+
```shell
|
|
45
|
+
python -m pip install onair
|
|
46
|
+
onair
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or run it without installing by using [uv](https://docs.astral.sh/uv/):
|
|
50
|
+
|
|
51
|
+
```shell
|
|
52
|
+
uvx onair
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
To run the source:
|
|
56
|
+
|
|
57
|
+
```shell
|
|
58
|
+
uv sync
|
|
59
|
+
uv run onair
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Then choose a genre or country and start exploring:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
onair> help
|
|
66
|
+
onair> play chillout
|
|
67
|
+
onair> info
|
|
68
|
+
onair> next
|
|
69
|
+
onair> previous
|
|
70
|
+
onair> country poland
|
|
71
|
+
onair> volume +10
|
|
72
|
+
onair> pause
|
|
73
|
+
onair> resume
|
|
74
|
+
onair> stop
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Run `help` for every command and `help play` for command-specific examples. Running `play` without a genre resumes paused playback or chooses a genre at random.
|
|
78
|
+
|
|
79
|
+
## Acknowledgments
|
|
80
|
+
|
|
81
|
+
Inspired by cmd.fm. onair is an independent project and is not affiliated with or endorsed by cmd.fm.
|
|
82
|
+
|
|
83
|
+
## Development
|
|
84
|
+
|
|
85
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the development workflow and release process.
|
|
86
|
+
|
|
87
|
+
## License
|
|
88
|
+
|
|
89
|
+
Licensed under the [MIT License](LICENSE).
|
onair-1.0.1/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# onair
|
|
2
|
+
|
|
3
|
+
[](https://github.com/roman-kaczanowski/onair/actions/workflows/quality-checks.yml) [](https://pypi.org/project/onair/) [](https://docs.python.org/3/) [](LICENSE)
|
|
4
|
+
|
|
5
|
+
Turn your terminal into an internet radio. onair is a small interactive shell for finding and playing stations by genre or country.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Browse popular genres and countries.
|
|
10
|
+
- Jump between stations and return to recently played ones.
|
|
11
|
+
- Pause, resume, mute, and adjust volume without leaving the prompt.
|
|
12
|
+
- Use tab completion, command history, and short aliases.
|
|
13
|
+
- Discover stations through [Radio Browser](https://www.radio-browser.info/) without an API key.
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
- Python 3.12 or newer.
|
|
18
|
+
- [VLC](https://www.videolan.org/vlc/) installed on your system. The `python-vlc` binding is installed with onair, but playback still requires the VLC application and its native library.
|
|
19
|
+
|
|
20
|
+
## Quick start
|
|
21
|
+
|
|
22
|
+
Install the release from PyPI:
|
|
23
|
+
|
|
24
|
+
```shell
|
|
25
|
+
python -m pip install onair
|
|
26
|
+
onair
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or run it without installing by using [uv](https://docs.astral.sh/uv/):
|
|
30
|
+
|
|
31
|
+
```shell
|
|
32
|
+
uvx onair
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
To run the source:
|
|
36
|
+
|
|
37
|
+
```shell
|
|
38
|
+
uv sync
|
|
39
|
+
uv run onair
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then choose a genre or country and start exploring:
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
onair> help
|
|
46
|
+
onair> play chillout
|
|
47
|
+
onair> info
|
|
48
|
+
onair> next
|
|
49
|
+
onair> previous
|
|
50
|
+
onair> country poland
|
|
51
|
+
onair> volume +10
|
|
52
|
+
onair> pause
|
|
53
|
+
onair> resume
|
|
54
|
+
onair> stop
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Run `help` for every command and `help play` for command-specific examples. Running `play` without a genre resumes paused playback or chooses a genre at random.
|
|
58
|
+
|
|
59
|
+
## Acknowledgments
|
|
60
|
+
|
|
61
|
+
Inspired by cmd.fm. onair is an independent project and is not affiliated with or endorsed by cmd.fm.
|
|
62
|
+
|
|
63
|
+
## Development
|
|
64
|
+
|
|
65
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the development workflow and release process.
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
Licensed under the [MIT License](LICENSE).
|