coverart-cli 0.4.0__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.
- coverart_cli-0.4.0/.coderabbit.yaml +38 -0
- coverart_cli-0.4.0/.editorconfig +17 -0
- coverart_cli-0.4.0/.github/CODEOWNERS +2 -0
- coverart_cli-0.4.0/.github/dependabot.yml +18 -0
- coverart_cli-0.4.0/.github/workflows/auto-enable-automerge.yml +23 -0
- coverart_cli-0.4.0/.github/workflows/ci.yml +84 -0
- coverart_cli-0.4.0/.github/workflows/codeql.yml +33 -0
- coverart_cli-0.4.0/.github/workflows/dependabot-automerge.yml +28 -0
- coverart_cli-0.4.0/.github/workflows/release-please.yml +20 -0
- coverart_cli-0.4.0/.github/workflows/release.yml +61 -0
- coverart_cli-0.4.0/.gitignore +47 -0
- coverart_cli-0.4.0/.pre-commit-config.yaml +18 -0
- coverart_cli-0.4.0/.release-please-manifest.json +3 -0
- coverart_cli-0.4.0/CHANGELOG.md +98 -0
- coverart_cli-0.4.0/LICENSE +21 -0
- coverart_cli-0.4.0/PKG-INFO +160 -0
- coverart_cli-0.4.0/README.md +128 -0
- coverart_cli-0.4.0/SECURITY.md +23 -0
- coverart_cli-0.4.0/docs/make_demo_report.py +97 -0
- coverart_cli-0.4.0/docs/screenshots/report-dark.png +0 -0
- coverart_cli-0.4.0/docs/screenshots/report-light.png +0 -0
- coverart_cli-0.4.0/pyproject.toml +65 -0
- coverart_cli-0.4.0/release-please-config.json +32 -0
- coverart_cli-0.4.0/src/coverart_cli/__init__.py +47 -0
- coverart_cli-0.4.0/src/coverart_cli/__main__.py +4 -0
- coverart_cli-0.4.0/src/coverart_cli/cli.py +257 -0
- coverart_cli-0.4.0/src/coverart_cli/config.py +91 -0
- coverart_cli-0.4.0/src/coverart_cli/core.py +320 -0
- coverart_cli-0.4.0/src/coverart_cli/providers/__init__.py +15 -0
- coverart_cli-0.4.0/src/coverart_cli/providers/base.py +73 -0
- coverart_cli-0.4.0/src/coverart_cli/providers/deezer.py +48 -0
- coverart_cli-0.4.0/src/coverart_cli/providers/itunes.py +59 -0
- coverart_cli-0.4.0/src/coverart_cli/providers/lastfm.py +72 -0
- coverart_cli-0.4.0/src/coverart_cli/providers/musicbrainz.py +78 -0
- coverart_cli-0.4.0/src/coverart_cli/py.typed +0 -0
- coverart_cli-0.4.0/src/coverart_cli/report.py +180 -0
- coverart_cli-0.4.0/src/coverart_cli/tagging.py +230 -0
- coverart_cli-0.4.0/src/coverart_cli/templates/report.html +450 -0
- coverart_cli-0.4.0/tests/__init__.py +0 -0
- coverart_cli-0.4.0/tests/test_config.py +47 -0
- coverart_cli-0.4.0/tests/test_integration.py +225 -0
- coverart_cli-0.4.0/tests/test_providers.py +62 -0
- coverart_cli-0.4.0/tests/test_report.py +138 -0
- coverart_cli-0.4.0/tests/test_tagging.py +57 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# CodeRabbit configuration for coverart-cli
|
|
2
|
+
# Docs: https://docs.coderabbit.ai/getting-started/configure-coderabbit
|
|
3
|
+
|
|
4
|
+
language: en-US
|
|
5
|
+
early_access: false
|
|
6
|
+
|
|
7
|
+
reviews:
|
|
8
|
+
profile: chill # less nitpicky; chill | assertive
|
|
9
|
+
request_changes_workflow: false
|
|
10
|
+
high_level_summary: true
|
|
11
|
+
poem: false
|
|
12
|
+
review_status: true
|
|
13
|
+
collapse_walkthrough: true
|
|
14
|
+
auto_review:
|
|
15
|
+
enabled: true
|
|
16
|
+
drafts: false
|
|
17
|
+
base_branches: [main]
|
|
18
|
+
path_filters:
|
|
19
|
+
- "!docs/screenshots/**" # don't review screenshots
|
|
20
|
+
- "!**/*.md" # docs don't need code review
|
|
21
|
+
- "!CHANGELOG.md"
|
|
22
|
+
- "!.release-please-manifest.json"
|
|
23
|
+
path_instructions:
|
|
24
|
+
- path: "src/coverart_cli/providers/**"
|
|
25
|
+
instructions: >
|
|
26
|
+
Providers must inherit CoverProvider and call _http_get with retries.
|
|
27
|
+
Reject placeholder images. Respect MIN_COVER_BYTES.
|
|
28
|
+
- path: "src/coverart_cli/templates/**"
|
|
29
|
+
instructions: >
|
|
30
|
+
HTML templates must use safe DOM construction
|
|
31
|
+
(createElement / textContent / replaceChildren),
|
|
32
|
+
never innerHTML with non-escaped JSON.
|
|
33
|
+
- path: "tests/**"
|
|
34
|
+
instructions: >
|
|
35
|
+
Tests should be deterministic — use the FakeProvider, no real network.
|
|
36
|
+
|
|
37
|
+
chat:
|
|
38
|
+
auto_reply: true
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset = utf-8
|
|
5
|
+
end_of_line = lf
|
|
6
|
+
insert_final_newline = true
|
|
7
|
+
trim_trailing_whitespace = true
|
|
8
|
+
indent_style = space
|
|
9
|
+
|
|
10
|
+
[*.py]
|
|
11
|
+
indent_size = 4
|
|
12
|
+
|
|
13
|
+
[*.{json,toml,yml,yaml,html,css,js}]
|
|
14
|
+
indent_size = 2
|
|
15
|
+
|
|
16
|
+
[Makefile]
|
|
17
|
+
indent_style = tab
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "github-actions"
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "weekly"
|
|
7
|
+
open-pull-requests-limit: 5
|
|
8
|
+
groups:
|
|
9
|
+
gh-actions:
|
|
10
|
+
patterns: ["*"]
|
|
11
|
+
- package-ecosystem: "pip"
|
|
12
|
+
directory: "/"
|
|
13
|
+
schedule:
|
|
14
|
+
interval: "weekly"
|
|
15
|
+
open-pull-requests-limit: 5
|
|
16
|
+
groups:
|
|
17
|
+
python-deps:
|
|
18
|
+
patterns: ["*"]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Auto-enable squash auto-merge on every non-draft PR.
|
|
2
|
+
# Branch protection still gates the merge — it only fires once all required
|
|
3
|
+
# checks (test matrix, CodeQL, smoke, CodeRabbit) pass.
|
|
4
|
+
name: Enable auto-merge
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
pull_request_target:
|
|
8
|
+
types: [opened, reopened, ready_for_review]
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: write
|
|
12
|
+
pull-requests: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
enable:
|
|
16
|
+
if: github.event.pull_request.draft == false
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- name: Enable squash auto-merge
|
|
20
|
+
env:
|
|
21
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
22
|
+
PR_URL: ${{ github.event.pull_request.html_url }}
|
|
23
|
+
run: gh pr merge --auto --squash "$PR_URL"
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
name: test (py${{ matrix.python-version }})
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v6
|
|
22
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
23
|
+
uses: actions/setup-python@v6
|
|
24
|
+
with:
|
|
25
|
+
python-version: ${{ matrix.python-version }}
|
|
26
|
+
cache: pip
|
|
27
|
+
cache-dependency-path: pyproject.toml
|
|
28
|
+
- name: Install
|
|
29
|
+
run: |
|
|
30
|
+
python -m pip install --upgrade pip
|
|
31
|
+
pip install -e ".[dev]"
|
|
32
|
+
- name: Lint
|
|
33
|
+
run: ruff check .
|
|
34
|
+
- name: Unit + integration tests
|
|
35
|
+
run: pytest --cov=coverart_cli --cov-report=term-missing
|
|
36
|
+
|
|
37
|
+
smoke:
|
|
38
|
+
name: smoke (install wheel + run end-to-end)
|
|
39
|
+
needs: test
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@v6
|
|
43
|
+
- uses: actions/setup-python@v6
|
|
44
|
+
with:
|
|
45
|
+
python-version: "3.12"
|
|
46
|
+
cache: pip
|
|
47
|
+
cache-dependency-path: pyproject.toml
|
|
48
|
+
- name: Build wheel
|
|
49
|
+
run: |
|
|
50
|
+
python -m pip install --upgrade pip build
|
|
51
|
+
python -m build --wheel
|
|
52
|
+
- name: Install wheel into a fresh venv
|
|
53
|
+
run: |
|
|
54
|
+
python -m venv /tmp/smoke-venv
|
|
55
|
+
/tmp/smoke-venv/bin/pip install --upgrade pip
|
|
56
|
+
/tmp/smoke-venv/bin/pip install dist/*.whl
|
|
57
|
+
- name: Verify CLI is installed
|
|
58
|
+
run: |
|
|
59
|
+
/tmp/smoke-venv/bin/coverart --version
|
|
60
|
+
/tmp/smoke-venv/bin/coverart --help > /dev/null
|
|
61
|
+
- name: Build a fixture library
|
|
62
|
+
# Use the smoke-venv python so we can import mutagen (installed as a dep of coverart-cli).
|
|
63
|
+
run: |
|
|
64
|
+
/tmp/smoke-venv/bin/python <<'PY'
|
|
65
|
+
from pathlib import Path
|
|
66
|
+
from mutagen.id3 import ID3, TPE1, TPE2, TALB, TIT2
|
|
67
|
+
p = Path("/tmp/fixture-lib/Pink Floyd/The Wall/01.mp3")
|
|
68
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
69
|
+
p.write_bytes(b"\xff\xfb\x90\x00" + b"\x00" * 1000)
|
|
70
|
+
tags = ID3()
|
|
71
|
+
tags.add(TPE1(encoding=3, text=["Pink Floyd"]))
|
|
72
|
+
tags.add(TPE2(encoding=3, text=["Pink Floyd"]))
|
|
73
|
+
tags.add(TALB(encoding=3, text=["The Wall"]))
|
|
74
|
+
tags.add(TIT2(encoding=3, text=["Mother"]))
|
|
75
|
+
tags.save(str(p))
|
|
76
|
+
PY
|
|
77
|
+
- name: Run end-to-end
|
|
78
|
+
run: |
|
|
79
|
+
/tmp/smoke-venv/bin/coverart /tmp/fixture-lib -v
|
|
80
|
+
test -f "/tmp/fixture-lib/Pink Floyd/The Wall/cover.jpg" && echo "✓ cover.jpg written"
|
|
81
|
+
- name: Generate HTML report against fixture
|
|
82
|
+
run: |
|
|
83
|
+
/tmp/smoke-venv/bin/coverart /tmp/fixture-lib --report-only --report-html /tmp/report.html
|
|
84
|
+
test -s /tmp/report.html && echo "✓ report written ($(wc -c </tmp/report.html) bytes)"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: CodeQL
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
schedule:
|
|
9
|
+
# Weekly extra scan to catch newly disclosed CVEs in dependencies.
|
|
10
|
+
- cron: "13 7 * * 1"
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
security-events: write
|
|
15
|
+
actions: read
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
analyze:
|
|
19
|
+
name: Analyze (python)
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v6
|
|
23
|
+
- name: Initialize CodeQL
|
|
24
|
+
uses: github/codeql-action/init@v4
|
|
25
|
+
with:
|
|
26
|
+
languages: python
|
|
27
|
+
queries: security-extended,security-and-quality
|
|
28
|
+
- name: Autobuild
|
|
29
|
+
uses: github/codeql-action/autobuild@v4
|
|
30
|
+
- name: Perform analysis
|
|
31
|
+
uses: github/codeql-action/analyze@v4
|
|
32
|
+
with:
|
|
33
|
+
category: "/language:python"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Auto-merge Dependabot PRs once all required checks pass.
|
|
2
|
+
# Branch protection requires the status checks (test matrix + CodeQL + smoke);
|
|
3
|
+
# this workflow just flips the auto-merge bit, GitHub does the rest.
|
|
4
|
+
name: Dependabot auto-merge
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
pull_request_target:
|
|
8
|
+
types: [opened, reopened, synchronize, ready_for_review]
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: write
|
|
12
|
+
pull-requests: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
automerge:
|
|
16
|
+
if: github.actor == 'dependabot[bot]'
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- name: Fetch Dependabot metadata
|
|
20
|
+
id: meta
|
|
21
|
+
uses: dependabot/fetch-metadata@v2
|
|
22
|
+
with:
|
|
23
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
24
|
+
- name: Enable auto-merge (squash)
|
|
25
|
+
env:
|
|
26
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
27
|
+
PR_URL: ${{ github.event.pull_request.html_url }}
|
|
28
|
+
run: gh pr merge --auto --squash "$PR_URL"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Release-please
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: write
|
|
9
|
+
pull-requests: write
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
release-please:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: googleapis/release-please-action@v4
|
|
17
|
+
id: release
|
|
18
|
+
with:
|
|
19
|
+
config-file: release-please-config.json
|
|
20
|
+
manifest-file: .release-please-manifest.json
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: Release to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
id-token: write # PyPI Trusted Publishing (OIDC)
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
# Gate: must pass tests before we ever build a release artifact.
|
|
13
|
+
test:
|
|
14
|
+
name: test (py${{ matrix.python-version }})
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: true
|
|
18
|
+
matrix:
|
|
19
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v6
|
|
22
|
+
- uses: actions/setup-python@v6
|
|
23
|
+
with:
|
|
24
|
+
python-version: ${{ matrix.python-version }}
|
|
25
|
+
cache: pip
|
|
26
|
+
- run: |
|
|
27
|
+
python -m pip install --upgrade pip
|
|
28
|
+
pip install -e ".[dev]"
|
|
29
|
+
- run: ruff check .
|
|
30
|
+
- run: pytest
|
|
31
|
+
|
|
32
|
+
build:
|
|
33
|
+
needs: test
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@v6
|
|
37
|
+
- uses: actions/setup-python@v6
|
|
38
|
+
with:
|
|
39
|
+
python-version: "3.12"
|
|
40
|
+
- run: python -m pip install --upgrade pip build
|
|
41
|
+
- run: python -m build
|
|
42
|
+
- uses: actions/upload-artifact@v7
|
|
43
|
+
with:
|
|
44
|
+
name: dist
|
|
45
|
+
path: dist/
|
|
46
|
+
|
|
47
|
+
publish:
|
|
48
|
+
needs: build
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
environment:
|
|
51
|
+
name: pypi
|
|
52
|
+
url: https://pypi.org/p/coverart-cli
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/download-artifact@v8
|
|
55
|
+
with:
|
|
56
|
+
name: dist
|
|
57
|
+
path: dist/
|
|
58
|
+
# Pinned to a release tag; bump deliberately, signed by maintainer.
|
|
59
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
60
|
+
with:
|
|
61
|
+
attestations: true
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
*.egg
|
|
11
|
+
.eggs/
|
|
12
|
+
|
|
13
|
+
# venv
|
|
14
|
+
.venv/
|
|
15
|
+
venv/
|
|
16
|
+
env/
|
|
17
|
+
ENV/
|
|
18
|
+
|
|
19
|
+
# Test / coverage
|
|
20
|
+
.pytest_cache/
|
|
21
|
+
.coverage
|
|
22
|
+
.coverage.*
|
|
23
|
+
htmlcov/
|
|
24
|
+
.tox/
|
|
25
|
+
.ruff_cache/
|
|
26
|
+
.mypy_cache/
|
|
27
|
+
|
|
28
|
+
# IDE
|
|
29
|
+
.vscode/
|
|
30
|
+
.idea/
|
|
31
|
+
*.swp
|
|
32
|
+
*~
|
|
33
|
+
|
|
34
|
+
# OS
|
|
35
|
+
.DS_Store
|
|
36
|
+
Thumbs.db
|
|
37
|
+
|
|
38
|
+
# Local
|
|
39
|
+
*.local
|
|
40
|
+
.env
|
|
41
|
+
.envrc
|
|
42
|
+
|
|
43
|
+
# Project output
|
|
44
|
+
missing-covers.csv
|
|
45
|
+
*.log
|
|
46
|
+
docs/screenshots/demo-report.html
|
|
47
|
+
docs/screenshots/*.tmp
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
|
+
rev: v5.0.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: check-yaml
|
|
6
|
+
- id: check-toml
|
|
7
|
+
- id: check-added-large-files
|
|
8
|
+
args: [--maxkb=2048]
|
|
9
|
+
- id: end-of-file-fixer
|
|
10
|
+
- id: trailing-whitespace
|
|
11
|
+
- id: check-merge-conflict
|
|
12
|
+
- id: mixed-line-ending
|
|
13
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
14
|
+
rev: v0.7.4
|
|
15
|
+
hooks:
|
|
16
|
+
- id: ruff
|
|
17
|
+
args: [--fix]
|
|
18
|
+
- id: ruff-format
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.4.0](https://github.com/WildDragonKing/coverart-cli/compare/v0.3.0...v0.4.0) (2026-05-17)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* add release-please for merge-driven version bumps ([#9](https://github.com/WildDragonKing/coverart-cli/issues/9)) ([28ec876](https://github.com/WildDragonKing/coverart-cli/commit/28ec8768d70e22c50ebd58e6ca170fb65393eb6c))
|
|
14
|
+
* auto-enable squash auto-merge + CodeRabbit config ([#11](https://github.com/WildDragonKing/coverart-cli/issues/11)) ([3756926](https://github.com/WildDragonKing/coverart-cli/commit/37569263e397e61d34d3cd865f4935c94432e3a9))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* drop failing approve step from Dependabot auto-merge ([#12](https://github.com/WildDragonKing/coverart-cli/issues/12)) ([c2f984d](https://github.com/WildDragonKing/coverart-cli/commit/c2f984d7417ee811bc80e90ec9b3d2f587ffddb2))
|
|
20
|
+
|
|
21
|
+
## [0.3.0] - 2026-05-17
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- **TOML config file** support — `~/.config/coverart-cli/config.toml`,
|
|
26
|
+
`./coverart.toml`, or `--config PATH`. CLI flags still override the config.
|
|
27
|
+
- **`py.typed`** marker file for PEP 561 — type checkers can now see our types.
|
|
28
|
+
- **Public library API** explicitly defined via `__all__` in
|
|
29
|
+
`coverart_cli/__init__.py`. You can now do
|
|
30
|
+
`from coverart_cli import RunOptions, run, ITunesProvider`.
|
|
31
|
+
- **`.editorconfig`** for cross-IDE consistency.
|
|
32
|
+
- **`.pre-commit-config.yaml`** with ruff + ruff-format + standard checks.
|
|
33
|
+
- **`SECURITY.md`** with private vulnerability reporting link.
|
|
34
|
+
- **PyPI release workflow** (`.github/workflows/release.yml`) — push a
|
|
35
|
+
`v*` tag and the package is built and uploaded via PyPI Trusted Publishing.
|
|
36
|
+
Includes a **`needs: test`** gate so a red main can't ship a release.
|
|
37
|
+
- **Dependabot** monthly checks for GitHub Actions and pip.
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- Minimum Python is now **3.11** (was 3.10) — needed for stdlib `tomllib`.
|
|
42
|
+
- Metadata now uses **PEP 639 SPDX** (`license = "MIT"` + `license-files`),
|
|
43
|
+
no more deprecated `License ::` classifier.
|
|
44
|
+
- Description and CLI help text now reflect the actual provider and format
|
|
45
|
+
coverage (4 providers, 5 formats).
|
|
46
|
+
- All providers share a single `_default_user_agent()` derived from
|
|
47
|
+
`__version__` — no more stale `0.1.0` strings hard-coded in defaults.
|
|
48
|
+
- `iTunesProvider` and `DeezerProvider` correctly accept `user_agent=`
|
|
49
|
+
(was silently ignored, broke library usage).
|
|
50
|
+
- `MusicBrainzProvider` dead `release` fallback branch removed.
|
|
51
|
+
- Size threshold for accepted covers unified across providers via
|
|
52
|
+
`tagging.MIN_COVER_BYTES`.
|
|
53
|
+
- `scan_library` path-traversal logic simplified to `relative_to` +
|
|
54
|
+
`ValueError` guard.
|
|
55
|
+
|
|
56
|
+
## [0.2.0] - 2026-05-17
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
|
|
60
|
+
- **iTunes provider** (Apple Music public search) — no API key required.
|
|
61
|
+
- **Deezer provider** — no API key required.
|
|
62
|
+
- **FLAC, Ogg Vorbis, and Opus** file format support (read + embed).
|
|
63
|
+
- HTML report shows iTunes / Deezer / Embedded filter chips and badges.
|
|
64
|
+
- Demo report generator (`docs/make_demo_report.py`).
|
|
65
|
+
- **`--min-bytes N`**: upgrade existing covers smaller than N bytes. Default 0
|
|
66
|
+
(keep all existing). Setting e.g. `--min-bytes 50000` causes the tool to
|
|
67
|
+
re-fetch covers for any album whose current artwork is below 50 KB.
|
|
68
|
+
- **`--replace-smaller`**: when the freshly fetched cover is larger than the
|
|
69
|
+
existing one, replace it. Default is to keep the larger existing cover when
|
|
70
|
+
both qualify.
|
|
71
|
+
- `existing_embedded_size()` helper in `coverart_cli.tagging` for inspecting
|
|
72
|
+
in-tag artwork sizes across all five formats.
|
|
73
|
+
|
|
74
|
+
### Changed
|
|
75
|
+
|
|
76
|
+
- Last.fm is now optional — if no key is supplied, the tool runs with the three
|
|
77
|
+
free providers instead of failing.
|
|
78
|
+
- README rewritten — significantly shorter, with screenshots and an
|
|
79
|
+
alternatives table.
|
|
80
|
+
|
|
81
|
+
## [0.1.0] - 2026-05-17
|
|
82
|
+
|
|
83
|
+
### Added
|
|
84
|
+
|
|
85
|
+
- Initial release.
|
|
86
|
+
- Tag-first album metadata reading via `mutagen`, directory-name fallback.
|
|
87
|
+
- Last.fm `album.getinfo` provider with placeholder-image rejection.
|
|
88
|
+
- MusicBrainz + Cover Art Archive fallback provider with rate limiting.
|
|
89
|
+
- Embed into MP3 (`ID3 APIC`) and M4A (`covr` atom).
|
|
90
|
+
- Sidecar `cover.jpg` / `cover.png` writing with magic-byte MIME detection.
|
|
91
|
+
- CLI: `--lastfm-key`, `--no-lastfm`, `--no-musicbrainz`, `--no-embed`,
|
|
92
|
+
`--no-sidecar`, `--dry-run`, `--missing-csv`, `-v`/`-vv`.
|
|
93
|
+
- **HTML coverage report**: `--report-html PATH`, `--report-only`, `--no-thumbs`.
|
|
94
|
+
Self-contained single-file output with embedded thumbnails, dark/light theme,
|
|
95
|
+
searchable + filterable album grid. Editorial/liner-notes aesthetic with
|
|
96
|
+
Fraunces, Geist, and JetBrains Mono typography.
|
|
97
|
+
- Pytest smoke suite (25 tests) for tagging, provider helpers, and report module.
|
|
98
|
+
- GitHub Actions CI for lint + tests on Python 3.10–3.13.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 WildDragonKing
|
|
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.
|