Skip to content

refactor(content): reorganize demo content and add one_to_rule article - #80

Closed
Andreas-Garcia wants to merge 26 commits into
mainfrom
feature/one-to-rule-demo-video
Closed

refactor(content): reorganize demo content and add one_to_rule article#80
Andreas-Garcia wants to merge 26 commits into
mainfrom
feature/one-to-rule-demo-video

Conversation

@Andreas-Garcia

Copy link
Copy Markdown
Member

Description

Reorganizes demo/content tooling under a single content/ hub and adds the "one to rule them all" article: a hero video comparing audiometa's unified reading against other tools (RIFF, ID3v2, ID3v1, Vorbis), plus side-by-side GIF generation and supporting scripts. Also fixes DISC_NUMBER's optional type to allow None, matching DISC_TOTAL.

Key changes:

Content restructuring

  • content/demo/: New hub for library demo docs (docs/), demo-only scripts (scripts/), and shared tapes/output (demos/). Replaces the old docs/demos/ and root-level scripts/demo_repl.py / scripts/run_demo_tape.py.
  • content/articles/: New home for per-article content, each with its own tapes/, samples/, scripts/, and output/ (work/ for intermediates, final/ for deliverables).
  • .gitignore: Reworked to ignore generated GIF/MP4/WAV/FLAC/MP3 output under content/**/output/ and loose article files, while explicitly tracking article scripts and whitelisted samples/sample.{mp3,flac,wav}.
  • .pre-commit-config.yaml: check-added-large-files now also excludes content/articles/*/samples/, since the whitelisted demo audio (FLAC/WAV) can exceed 10MB.

New article: one_to_rule

  • Hero video build: content/articles/one_to_rule/scripts/generate_one_to_rule_video.sh composes the intro + four reading comparisons into output/final/one_to_rule_them_all.mp4.
  • Supporting scripts: ensure_demo_read_id3v1.py (builds an ID3v1-only sample), print_id3v1_tags.py (prints tags for the comparison panel), sync_article_sample_metadata.py (aligns tags across sample formats), run_demo_side_by_side.sh / run_demo_side_by_side_vorbis.sh, run_vhs_tape.sh.
  • VHS tapes: before/after and read/write comparison tapes for RIFF, ID3v1, Vorbis, and combined scenarios.
  • Tracked samples: samples/sample.mp3, samples/sample.flac, samples/sample.wav (same underlying track).
  • Assets: assets/logo.mp4 (intro logo video).

Fix

  • UnifiedMetadataKey optional types: DISC_NUMBER is now int | None (was int), so files without a disc number validate consistently with DISC_TOTAL.

Docs

  • README.md: New ecosystem section with portfolio links (themusictree.org, AudioMeta Python project page, the-music-tree-frontend).
  • CHANGELOG.md: Entries for the demo layout move and the DISC_NUMBER fix.
  • .cursor/rules/demo-videos.mdc, .cursor/rules/demo-tape-authoring.mdc: Updated for the new content/ paths.

Related Issues

None

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring (no functional changes)
  • Performance improvement
  • Test addition/update
  • CI/CD or infrastructure change

Pre-PR Checklist

Code Quality

  • Removed commented-out code
  • No hardcoded credentials, API keys, or secrets
  • Ran pre-commit hooks: pre-commit run --all-files

Tests

  • All tests pass: pytest
  • Coverage meets threshold (≥85%): pytest --cov=audiometa --cov-report=term-missing --cov-fail-under=85
  • New features have corresponding tests
  • Bug fixes include regression tests

Documentation

  • Updated docstrings for new functions/classes (only when needed)
  • Updated README if adding new features or changing behavior
  • Updated CONTRIBUTING.md if changing development workflow
  • Added/updated type hints where appropriate

Git Hygiene

  • Commit messages follow the commit message convention
  • No merge conflicts with target branch
  • Branch is up to date with target branch
  • No accidental commits (large files, secrets, personal configs)

Breaking Changes

  • This PR includes breaking changes
  • Breaking changes are clearly documented below
  • Migration path is provided (if applicable)

Breaking Changes Description

N/A — docs/demos/ and root-level demo scripts are moved, not part of the public library API.

Testing Instructions

How to Test

  1. Hero video: bash content/articles/one_to_rule/scripts/generate_one_to_rule_video.sh (requires ffmpeg, ffprobe, metaflac, mid3v2, vhs); confirm content/articles/one_to_rule/output/final/one_to_rule_them_all.mp4.
  2. Library demo: python content/demo/scripts/run_demo_tape.py (or vhs content/demo/demos/tapes/audiometa_demo.tape); confirm output under content/demo/demos/output/.
  3. DISC_NUMBER fix: read a file with no disc number set and confirm disc_number validates as None instead of raising.

Test Results

(Add after running the steps above.)

Additional Context

  • This branch carries several Merge branch 'main' into ... commits from being kept in sync over time; the diff against main is the net set of changes above.

Checklist for Reviewers

  • Code follows project conventions and style
  • Logic is sound and well-structured
  • Error handling is appropriate
  • CI tests pass on all platforms and Python versions
  • Test coverage is adequate for the changes
  • Public API changes are documented
  • Breaking changes are clearly marked and documented
  • All review comments are addressed
  • No unresolved discussions

…vantages over other tools

- Introduced a new section comparing AudioMeta with mutagen, eyed3, and mid3v2/vorbiscomment.
- Highlighted features such as unified API, merged multi-format read, and CLI integration.
- Updated .gitignore to exclude generated demo outputs from version control, now located under content/articles/.
- Revised AGENTS.md and DEMO_INSTALLATION.md to reflect new paths for demo tapes and outputs.
- Enhanced demo authoring guidelines in .cursor/rules/demo-tape-authoring.mdc and demo video documentation in .cursor/rules/demo-videos.mdc.
- Introduced a new content/articles/README.md to clarify the structure and usage of article-specific demo assets.
- Adjusted paths in pyproject.toml and other related documentation to align with the new content organization.
- Deleted obsolete demo files including README.md, sample audio, and demo tapes.
- Updated installation script to reflect new paths for demo tapes.
- Cleaned up the demo directory structure to enhance organization and clarity.
- Revised the video generation script to reflect changes in the structure and content of the video, including updated dimensions and layout for the intro and content pages.
- Adjusted the script to build GIFs for reading and writing metadata, focusing on ID3v2, RIFF, ID3v1, and Vorbis formats.
- Updated the accompanying documentation to clarify the new structure of the video, including the transition from a 2x2 grid to a side-by-side panel layout for better comparison of formats.
- Updated the video generation script to ensure all cell GIFs are sourced from tapes, eliminating the use of placeholders. The script now fails early if any required output is missing.
- Revised documentation in AGENTS.md, .cursor/rules/demo-tape-authoring.mdc, and .cursor/rules/demo-videos.mdc to clarify the new requirements for demo panels and the structure of the hero video.
- Improved README.md to reflect changes in prerequisites and the overall build process, emphasizing the need for all tapes to run successfully for the hero video generation.
- Removed output directory from .gitignore to allow tracking of generated files.
- Enhanced error handling in video generation and VHS tape scripts to ensure the virtual environment is activated and dependencies are installed before execution.
- Updated metadata key type for DISC_NUMBER to support None values.
- Added clear command and sleep intervals in tape scripts for better readability during execution.
- Updated `.gitignore` to explicitly track scripts related to the hero video in `one_to_rule/`.
- Changed references in demo scripts and documentation to use `samples/sample.mp3` and `samples/sample.flac` for consistency.
- Enhanced README files to clarify the structure and usage of audio files within the article directory.
- Removed unnecessary `clear` commands from tape scripts to improve output clarity.
- Introduced `ensure_demo_read_id3v1.py` to create a demo MP3 file with ID3v1 tags.
- Added `print_id3v1_tags.py` to extract and display ID3v1 tag information from the generated demo file.
- Created `generate_one_to_rule_video.sh` to automate video generation, including GIF creation and side-by-side comparisons for audio metadata.
- Implemented `run_demo_side_by_side.sh` and `run_demo_side_by_side_vorbis.sh` for visual comparisons of audio metadata extraction methods.
- Added `sync_article_sample_metadata.py` to align audio sample metadata across formats.
- Enhanced error handling and documentation in the new scripts for clarity and usability.
- Moved demo-related scripts to a dedicated `scripts/` directory within the `one_to_rule/` article folder for better organization.
- Updated paths in scripts and documentation to reflect the new structure, ensuring consistency across references to audio samples and generated outputs.
- Enhanced README files to clarify the usage of scripts and the structure of the article directory.
- Improved error handling and documentation in the updated scripts for better usability and clarity.
- Updated the output directory structure in the `one_to_rule` article to separate final deliverables and intermediate files into `output/final/` and `output/work/`, respectively.
- Modified scripts to reflect the new output paths, ensuring clarity in the generation process for both GIFs and MP4 videos.
- Enhanced README documentation to clarify the changes in output organization and usage.
- Updated the `generate_one_to_rule_video.sh` script to allow specifying a custom final filename for the output video.
- Adjusted README files to reflect changes in output paths and usage instructions for video generation.
- Improved error handling and path management in demo scripts to ensure consistency and clarity across the project.
- Added best practices for video generation to the demo videos documentation, including guidelines for brand text color and immediate regeneration after visual changes.
- Updated the `generate_one_to_rule_video.sh` script to improve text color consistency and adjust logo handling for better visual output.
- Enhanced error handling for logo file checks and clarified comments in the script for improved usability.
…re .local/

- generate_one_to_rule_video.sh: reduce COMPARISON_FOOTER_DESCEND_PX 44 -> 12
- CHANGELOG.md: add Fixed entry for DISC_NUMBER optional type (int | None)
- .gitignore: ignore .local/ (generated PR description scratch files)
Copilot AI lite review requested due to automatic review settings August 6, 2026 16:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

…emo-video

# Conflicts:
#	CHANGELOG.md
#	pyproject.toml
@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies labels Aug 7, 2026
@Andreas-Garcia
Andreas-Garcia requested a lite review from Copilot August 7, 2026 10:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 51 out of 59 changed files in this pull request and generated 1 comment.

Suppressed comments (5)

content/demo/demos/tapes/audiometa_demo.tape:25

  • From content/demo/demos, cd ../.. lands in content/, not the repo root. This breaks subsequent commands/paths (e.g. audiometa/test/assets/..., content/demo/scripts/...).
    content/demo/demos/tapes/audiometa_demo_script.tape:23
  • From content/demo/demos, cd ../.. lands in content/, not the repo root, so cat content/demo/scripts/... and python content/demo/scripts/... will fail.
    content/demo/scripts/run_demo_tape.py:36
  • rel is assigned but never used, which will fail linting (unused variable).
    content/demo/demos/README.md:10
  • The README says the tapes run a hidden cd ../.. to reach repo root, but from content/demo/demos that only reaches content/. The correct path to repo root is cd ../../...
    audiometa/utils/unified_metadata_key.py:82
  • Changing DISC_NUMBER to return int | None from get_optional_type() will cause downstream code that checks opt is int (e.g. unified metadata field schema construction) to treat disc_number as a non-integer. If disc_number is intended to remain an integer field that may be null, the schema/value-shape logic should be updated accordingly (similar to DISC_TOTAL).
            UnifiedMetadataKey.GENRES_NAMES: list[str],
            UnifiedMetadataKey.RATING: int | float,
            UnifiedMetadataKey.LANGUAGE: str,
            UnifiedMetadataKey.RELEASE_DATE: str,
            UnifiedMetadataKey.TRACK_NUMBER: str,  # Can be int or str
            UnifiedMetadataKey.DISC_NUMBER: int | None,
            UnifiedMetadataKey.DISC_TOTAL: int | None,
            UnifiedMetadataKey.BPM: int,
            UnifiedMetadataKey.COMPOSERS: list[str],

Comment on lines +74 to +80
args = parser.parse_args()

repo_root = Path(__file__).resolve().parent.parent.parent
articles_dir = repo_root / "content" / "articles"
if not articles_dir.is_dir():
print("Error: content/articles/ not found.", file=sys.stderr)
sys.exit(1)
Homebrew's media-info formula moved past the pinned version with no
older bottle available, failing the macOS test job's exact-version
check unrelated to this PR's content changes.
- Fix DISC_NUMBER field schema regression: get_optional_type() now
  returns int | None for DISC_NUMBER, which fell through the schema's
  `is int` check to value_type "string" / optional_value False.
  DISC_NUMBER now shares DISC_TOTAL's explicit schema branch.
- Fix repo_root resolution in run_demo_tape.py (was one .parent short,
  content/articles/ was never found) and remove unused rel variable.
- Fix cd ../.. -> cd ../../.. in both library demo tapes and their
  README so repo-root-relative paths in the recordings resolve
  correctly from content/demo/demos.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 54 out of 62 changed files in this pull request and generated no new comments.

Suppressed comments (3)

content/articles/one_to_rule/scripts/generate_one_to_rule_video.sh:102

  • The hero-video script hard-requires assets/logo-round.png, but the article README claims assets/logo.png is also acceptable. Since assets/logo.png exists, add a fallback so the build doesn’t fail unnecessarily if only one of the two logo files is present.
AUDIO_META_LOGO_STILL="$REPO_ROOT/assets/logo-round.png"
[[ -f "$AUDIO_META_LOGO_STILL" ]] || {
  echo "Error: static logo not found: assets/logo-round.png" >&2
  exit 1
}

system-dependencies-demo.toml:16

  • The installation instructions mention bash scripts/install-demo-dependencies-ubuntu.sh, but that script does not exist in this branch. This makes the demo dependency doc misleading for Ubuntu users; point to the canonical Ubuntu instructions instead.
    content/articles/one_to_rule/scripts/generate_one_to_rule_video.sh:56
  • The comment says the height is scaled to 85%, but the calculation uses 70%. Either the comment or the scaling constant should change; at minimum the comment should match the actual behavior to avoid future layout confusion.

This issue also appears on line 98 of the same file.

# Baseline cell height was 420; overall video height is 15% lower (85% scale).
BASE_CELL_H=420
CELL_H=$((BASE_CELL_H * 70 / 100))

- Add assets/logo.png fallback in generate_one_to_rule_video.sh to
  match the README's documented behavior; the script previously
  hard-required logo-round.png only.
- Fix stale comment claiming 85% scale when the code computes 70%.
- Fix system-dependencies-demo.toml install note pointing at a
  nonexistent scripts/install-demo-dependencies-ubuntu.sh.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 54 out of 62 changed files in this pull request and generated no new comments.

Suppressed comments (1)

audiometa/utils/unified_metadata_key.py:80

  • get_optional_type() now returns runtime typing objects like int | None (for DISC_NUMBER / DISC_TOTAL), but the method signature still advertises a concrete type[...] return. Updating the return annotation to object (or a dedicated alias for runtime typing objects) avoids implying callers will always receive a class/type object.
            UnifiedMetadataKey.TRACK_NUMBER: str,  # Can be int or str
            UnifiedMetadataKey.DISC_NUMBER: int | None,
            UnifiedMetadataKey.DISC_TOTAL: int | None,

Copilot review round 3: the annotation claimed type[int | float | str | list[str]],
but the map already returns non-type runtime objects (unions, generic aliases).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 63 changed files in this pull request and generated no new comments.

Suppressed comments (2)

content/demo/scripts/run_demo_tape.py:131

  • The Output ... line rewrite uses re.sub(...) without verifying a replacement occurred. If a tape is missing an Output directive (or uses a different casing/format), this will silently leave the tape unchanged and the script may write output somewhere unexpected. Consider using re.subn and failing fast when no replacement happens.
    content/articles/one_to_rule/scripts/print_id3v1_tags.py:27
  • Minor output formatting: Comment:{comment} is missing a space after the colon, unlike the other fields. This looks unintentional and makes the demo output harder to read.
    sys.stdout.write(f"Comment:{comment}\n")

- run_demo_tape.py: fail fast if a tape has no Output directive to rewrite
- print_id3v1_tags.py: fix missing space after "Comment:" label

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 63 changed files in this pull request and generated no new comments.

Suppressed comments (1)

content/articles/one_to_rule/scripts/ensure_demo_read_id3v1.py:10

  • _strip_id3v2() computes the ID3v2 tag size without masking synchsafe bytes, and doesn’t account for the optional v2.4 footer flag. This can miscompute the slice offset and leave ID3 bytes in the output (or skip too far) for some tags.
def _strip_id3v2(data: bytes) -> bytes:
    while len(data) >= 10 and data[:3] == b"ID3":
        size = (data[6] << 21) | (data[7] << 14) | (data[8] << 7) | data[9]
        data = data[10 + size :]
    return data

ensure_demo_read_id3v1.py: mask synchsafe size bytes and account for
the optional ID3v2.4 footer when stripping ID3v2 tags.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 63 changed files in this pull request and generated no new comments.

Suppressed comments (1)

content/demo/scripts/run_demo_tape.py:122

  • run_demo_tape.py is a general article tape runner, but it hard-codes the placeholder token name @@ONE_TO_RULE_ABS@@. This makes it harder to reuse for other articles and couples a shared tool to one specific article name.

@Andreas-Garcia

Copy link
Copy Markdown
Member Author

Closing in favor of 5 focused, stacked PRs — this branch bundled six unrelated concerns (CI pin fix, a real type bug, demo-tooling reorg, doc-only README additions, and a large new content deliverable) which made it hard to review as a whole.

Replacements:

Verified the union of the 5 branches' diffs matches this branch's diff against main, with the sole intentional exception of dropping the stray assets/logo.mp4.untacked.bak backup file (unreferenced anywhere).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies documentation Improvements or additions to documentation test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants