yt-tools-cli 0.0.0__tar.gz → 0.23.2__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.
- yt_tools_cli-0.23.2/.claude-plugin/plugin.json +28 -0
- yt_tools_cli-0.23.2/.github/workflows/ci.yml +66 -0
- yt_tools_cli-0.23.2/.github/workflows/release.yml +72 -0
- yt_tools_cli-0.23.2/.gitignore +23 -0
- yt_tools_cli-0.23.2/CHANGELOG.md +251 -0
- yt_tools_cli-0.23.2/CONTRIBUTING.md +70 -0
- yt_tools_cli-0.23.2/LICENSE +21 -0
- yt_tools_cli-0.23.2/PKG-INFO +649 -0
- yt_tools_cli-0.23.2/README.md +607 -0
- yt_tools_cli-0.23.2/hooks/hooks.json +19 -0
- yt_tools_cli-0.23.2/pyproject.toml +120 -0
- yt_tools_cli-0.23.2/scripts/check-core-install.sh +206 -0
- yt_tools_cli-0.23.2/scripts/check-metadata.py +157 -0
- yt_tools_cli-0.23.2/scripts/check-pypi-name.py +166 -0
- yt_tools_cli-0.23.2/scripts/ensure-install.ps1 +188 -0
- yt_tools_cli-0.23.2/scripts/ensure-install.py +67 -0
- yt_tools_cli-0.23.2/scripts/ensure-install.sh +167 -0
- yt_tools_cli-0.23.2/scripts/publish-check.py +232 -0
- yt_tools_cli-0.23.2/scripts/sync-version.py +173 -0
- yt_tools_cli-0.23.2/skills/using-yt-tools/SKILL.md +643 -0
- yt_tools_cli-0.23.2/tests/__init__.py +0 -0
- yt_tools_cli-0.23.2/tests/test_cache.py +143 -0
- yt_tools_cli-0.23.2/tests/test_check_metadata.py +168 -0
- yt_tools_cli-0.23.2/tests/test_cli_smoke.py +301 -0
- yt_tools_cli-0.23.2/tests/test_comments.py +152 -0
- yt_tools_cli-0.23.2/tests/test_core.py +165 -0
- yt_tools_cli-0.23.2/tests/test_distribution_name.py +77 -0
- yt_tools_cli-0.23.2/tests/test_doctor.py +784 -0
- yt_tools_cli-0.23.2/tests/test_failure_modes.py +49 -0
- yt_tools_cli-0.23.2/tests/test_frames.py +600 -0
- yt_tools_cli-0.23.2/tests/test_listen.py +561 -0
- yt_tools_cli-0.23.2/tests/test_markdown.py +138 -0
- yt_tools_cli-0.23.2/tests/test_meta.py +151 -0
- yt_tools_cli-0.23.2/tests/test_missing_extra.py +318 -0
- yt_tools_cli-0.23.2/tests/test_ocr.py +412 -0
- yt_tools_cli-0.23.2/tests/test_packaging.py +525 -0
- yt_tools_cli-0.23.2/tests/test_parse_interval.py +42 -0
- yt_tools_cli-0.23.2/tests/test_publish_check.py +166 -0
- yt_tools_cli-0.23.2/tests/test_pypi_name.py +157 -0
- yt_tools_cli-0.23.2/tests/test_search.py +287 -0
- yt_tools_cli-0.23.2/tests/test_skill_portable.py +101 -0
- yt_tools_cli-0.23.2/tests/test_transcript.py +232 -0
- yt_tools_cli-0.23.2/tests/test_version.py +274 -0
- yt_tools_cli-0.23.2/tests/test_watch.py +324 -0
- yt_tools_cli-0.23.2/yt_tools/__init__.py +86 -0
- yt_tools_cli-0.23.2/yt_tools/_metadata.py +60 -0
- yt_tools_cli-0.23.2/yt_tools/cache.py +103 -0
- yt_tools_cli-0.23.2/yt_tools/cli.py +145 -0
- yt_tools_cli-0.23.2/yt_tools/comments.py +203 -0
- yt_tools_cli-0.23.2/yt_tools/core.py +159 -0
- yt_tools_cli-0.23.2/yt_tools/doctor.py +483 -0
- yt_tools_cli-0.23.2/yt_tools/extras.py +134 -0
- yt_tools_cli-0.23.2/yt_tools/frames.py +597 -0
- yt_tools_cli-0.23.2/yt_tools/listen.py +842 -0
- yt_tools_cli-0.23.2/yt_tools/markdown.py +127 -0
- yt_tools_cli-0.23.2/yt_tools/meta.py +171 -0
- yt_tools_cli-0.23.2/yt_tools/ocr.py +296 -0
- yt_tools_cli-0.23.2/yt_tools/search.py +308 -0
- yt_tools_cli-0.23.2/yt_tools/transcript.py +164 -0
- yt_tools_cli-0.23.2/yt_tools/watch.py +288 -0
- yt_tools_cli-0.0.0/PKG-INFO +0 -36
- yt_tools_cli-0.0.0/README.md +0 -23
- yt_tools_cli-0.0.0/pyproject.toml +0 -23
- yt_tools_cli-0.0.0/setup.cfg +0 -4
- yt_tools_cli-0.0.0/yt_tools_cli.egg-info/PKG-INFO +0 -36
- yt_tools_cli-0.0.0/yt_tools_cli.egg-info/SOURCES.txt +0 -6
- yt_tools_cli-0.0.0/yt_tools_cli.egg-info/dependency_links.txt +0 -1
- yt_tools_cli-0.0.0/yt_tools_cli.egg-info/top_level.txt +0 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "yt-tools",
|
|
3
|
+
"displayName": "yt-tools",
|
|
4
|
+
"version": "0.23.2",
|
|
5
|
+
"description": "Iterative YouTube watching for agents: clean-markdown transcripts with [mm:ss] anchors, targeted frame extraction, FFT audio analysis (BPM, key, chord progression, spectral features), full-metadata extraction (description, chapters, most-replayed, counts, tags), comment scraping, and OCR over cached frames (RapidOCR PP-OCRv5) for silent-with-text videos. Light core (transcript / metadata / comments / search) with heavy stacks in [frames] and [audio] extras. Bundles the using-yt-tools skill and a SessionStart hook that auto-installs from the plugin's local clone via pipx (default [full] extras, fallback to [frames,audio]) and probes ffmpeg.",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Victor Kuznetsov",
|
|
8
|
+
"url": "https://github.com/kzntsv-dev"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/kzntsv-dev/yt-tools",
|
|
11
|
+
"repository": "https://github.com/kzntsv-dev/yt-tools",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"youtube",
|
|
15
|
+
"transcript",
|
|
16
|
+
"agent",
|
|
17
|
+
"claude",
|
|
18
|
+
"audio-analysis",
|
|
19
|
+
"fft",
|
|
20
|
+
"bpm",
|
|
21
|
+
"iterative",
|
|
22
|
+
"yt-dlp",
|
|
23
|
+
"ffmpeg",
|
|
24
|
+
"librosa"
|
|
25
|
+
],
|
|
26
|
+
"skills": "./skills/",
|
|
27
|
+
"hooks": "./hooks/hooks.json"
|
|
28
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
tests:
|
|
14
|
+
name: pytest (full extras)
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
# The heavy stacks are installed on purpose: a handful of tests exercise the
|
|
22
|
+
# real audio pipeline rather than a mock, and a suite that is red on a clean
|
|
23
|
+
# machine teaches everyone to ignore it. The light-core contract is covered
|
|
24
|
+
# by the gate job below, which runs without any extra.
|
|
25
|
+
- name: Install
|
|
26
|
+
run: pip install -e ".[full,test]"
|
|
27
|
+
- name: Unit + CLI smoke tests
|
|
28
|
+
run: pytest -q
|
|
29
|
+
|
|
30
|
+
build:
|
|
31
|
+
name: build (sdist + wheel, publishable metadata)
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v4
|
|
35
|
+
- uses: actions/setup-python@v5
|
|
36
|
+
with:
|
|
37
|
+
python-version: "3.12"
|
|
38
|
+
- name: Install build tooling
|
|
39
|
+
run: python -m pip install --upgrade build twine
|
|
40
|
+
# The release job builds these same artifacts on a tag. Running the build
|
|
41
|
+
# here too is cheap insurance: a packaging mistake should cost a red CI
|
|
42
|
+
# run, not a burned version number. v0.23.0 is the case in point — build
|
|
43
|
+
# green, `twine check` green, and PyPI answered 400 on upload because a
|
|
44
|
+
# `Requires-Dist` carried a direct reference (`bpm-detector @ git+…`).
|
|
45
|
+
- name: Build + twine check
|
|
46
|
+
run: |
|
|
47
|
+
python -m build
|
|
48
|
+
python -m twine check dist/*
|
|
49
|
+
- name: Publishable metadata (no direct refs, no dev-repo meta)
|
|
50
|
+
run: python scripts/check-metadata.py dist
|
|
51
|
+
- uses: actions/upload-artifact@v4
|
|
52
|
+
with:
|
|
53
|
+
name: dist
|
|
54
|
+
path: dist/
|
|
55
|
+
retention-days: 7
|
|
56
|
+
|
|
57
|
+
gate:
|
|
58
|
+
name: install contract (AC4/AC5)
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@v4
|
|
62
|
+
# Runs itself inside python:3.12-slim: core install without extras, once
|
|
63
|
+
# without ffmpeg and once with a real static one, then checks that `warn`
|
|
64
|
+
# and `missing` stay machine-distinguishable in one --json payload.
|
|
65
|
+
- name: Core-install gate
|
|
66
|
+
run: bash scripts/check-core-install.sh
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
# A release is a tag: `git tag v0.23.0 && git push origin v0.23.0`. The version in
|
|
4
|
+
# pyproject.toml must match the tag — publish-check (last job) fails the run when
|
|
5
|
+
# it does not, because a green build is not a published release.
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
tags: ["v*"]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
inputs:
|
|
11
|
+
version:
|
|
12
|
+
description: "Version to publish (must match pyproject.toml)"
|
|
13
|
+
required: true
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
build:
|
|
20
|
+
name: build sdist + wheel
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
- uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.12"
|
|
27
|
+
- name: Build
|
|
28
|
+
run: |
|
|
29
|
+
python -m pip install --upgrade build twine
|
|
30
|
+
python -m build
|
|
31
|
+
python -m twine check dist/*
|
|
32
|
+
# Last line of defence, on the exact artifacts about to be uploaded: the
|
|
33
|
+
# same check CI runs, because this is the run where a miss costs a version.
|
|
34
|
+
- name: Publishable metadata
|
|
35
|
+
run: python scripts/check-metadata.py dist
|
|
36
|
+
- uses: actions/upload-artifact@v4
|
|
37
|
+
with:
|
|
38
|
+
name: dist
|
|
39
|
+
path: dist/
|
|
40
|
+
|
|
41
|
+
publish:
|
|
42
|
+
name: publish to PyPI (trusted publishing)
|
|
43
|
+
needs: build
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
# No API token anywhere: PyPI trusts this workflow through OIDC. The
|
|
46
|
+
# environment name must match the trusted publisher configured for the
|
|
47
|
+
# project on PyPI (`pypi`).
|
|
48
|
+
environment: pypi
|
|
49
|
+
permissions:
|
|
50
|
+
id-token: write # the OIDC token the index exchanges for an upload grant
|
|
51
|
+
steps:
|
|
52
|
+
- uses: actions/download-artifact@v4
|
|
53
|
+
with:
|
|
54
|
+
name: dist
|
|
55
|
+
path: dist/
|
|
56
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
57
|
+
|
|
58
|
+
verify:
|
|
59
|
+
name: verify the release landed
|
|
60
|
+
needs: publish
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
steps:
|
|
63
|
+
- uses: actions/checkout@v4
|
|
64
|
+
- uses: actions/setup-python@v5
|
|
65
|
+
with:
|
|
66
|
+
python-version: "3.12"
|
|
67
|
+
# The point of the job: "uploaded" and "installable" are different claims.
|
|
68
|
+
- name: publish-check (is the version people install the version we tagged?)
|
|
69
|
+
run: |
|
|
70
|
+
version="${GITHUB_REF_NAME#v}"
|
|
71
|
+
[ -n "$version" ] || version="${{ inputs.version }}"
|
|
72
|
+
python scripts/publish-check.py --version "$version"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Build and run artifacts
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
.venv/
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
*.egg-info/
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
yt-cache/
|
|
10
|
+
|
|
11
|
+
# Development-only paths. They exist in the private development repository and
|
|
12
|
+
# must never appear here: this repository is a curated copy, not the dev tree.
|
|
13
|
+
AGENTS.md
|
|
14
|
+
CLAUDE.md
|
|
15
|
+
.wiki/
|
|
16
|
+
.tasks/
|
|
17
|
+
.brainstorm/
|
|
18
|
+
.archive/
|
|
19
|
+
.mappa
|
|
20
|
+
.mappa-manifest.json
|
|
21
|
+
.pi/
|
|
22
|
+
MEMORY.md
|
|
23
|
+
.mcp.json
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to yt-tools. Format follows [Keep a Changelog](https://keepachangelog.com/);
|
|
4
|
+
the project uses [Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
The version lives in exactly one place — `pyproject.toml` — and is propagated to
|
|
7
|
+
`.claude-plugin/plugin.json` and the skill frontmatter by `scripts/sync-version.py`.
|
|
8
|
+
Releases before 0.8.0 are summarized only in the git log.
|
|
9
|
+
|
|
10
|
+
## [Unreleased]
|
|
11
|
+
|
|
12
|
+
_(nothing yet)_
|
|
13
|
+
|
|
14
|
+
## [0.23.2] — 2026-09-13
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- `scripts/publish-check.py` no longer reports a false `version drift` seconds
|
|
19
|
+
after a successful upload. PyPI's *project-level* JSON API is CDN-cached
|
|
20
|
+
(`cache-control: max-age=900`), so the `verify` job — which runs about five
|
|
21
|
+
seconds after the publish step — read the previous version and failed the
|
|
22
|
+
`0.23.1` release run while the release itself was live and complete. The check
|
|
23
|
+
now asks the *version-scoped* endpoint (`/pypi/<name>/<version>/json`, a URL
|
|
24
|
+
that cannot be stale) first, and lets the project endpoint only explain. Same
|
|
25
|
+
failure class as the simple-index cache behind the 0.22.1 preflight note: the
|
|
26
|
+
source a check adjudicates on has to be one that cannot lag.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- The README and the skill lead with the PyPI install instead of the git URL:
|
|
31
|
+
`pipx install "yt-tools-cli[full]"`, a pinned form
|
|
32
|
+
(`pipx install "yt-tools-cli[full]==0.23.1"`), and an explicit note that the
|
|
33
|
+
distribution is `yt-tools-cli` while the project, the repository and every
|
|
34
|
+
command stay `yt-tools` (import name `yt_tools`).
|
|
35
|
+
- The *changing extras* advice is corrected: `pipx uninstall` and then install,
|
|
36
|
+
instead of `pipx install --force`. A forced reinstall on an existing venv was
|
|
37
|
+
observed leaving the new extras half-installed (`scenedetect` skipped entirely)
|
|
38
|
+
and resolving `librosa` 1.0 past its cap; `pipx runpip yt-tools-cli list` is
|
|
39
|
+
the check that sees it.
|
|
40
|
+
|
|
41
|
+
## [0.23.1] — 2026-09-13
|
|
42
|
+
|
|
43
|
+
> `0.23.0` never reached PyPI: the upload was rejected and no artifact exists
|
|
44
|
+
> for it, so the first installable version is this one.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- **PyPI rejected the `0.23.0` upload with `400 Can't have direct dependency`.**
|
|
49
|
+
`[full]` carried `bpm-detector @ git+…` — a PEP 508 direct reference — and PyPI
|
|
50
|
+
refuses those in `Requires-Dist`. `python -m build` and `twine check` both
|
|
51
|
+
accept them, so the failure existed only on the tag. `[full]` is now core +
|
|
52
|
+
`[frames]` + `[audio]`; the plugin hook injects bpm-detector on top of it
|
|
53
|
+
best-effort, and a PyPI install adds it with `pipx inject yt-tools-cli …`
|
|
54
|
+
(README, *Installing bpm-detector*). Without it `yt-listen` still runs —
|
|
55
|
+
librosa-only BPM/key, with the sections it cannot fill marked `n/a`.
|
|
56
|
+
- `[tool.hatch.metadata] allow-direct-references` is gone. It is what let the
|
|
57
|
+
rejected metadata build at all; with no direct references left it is dead
|
|
58
|
+
weight, and keeping it off means the next one fails at `python -m build`.
|
|
59
|
+
|
|
60
|
+
### Added
|
|
61
|
+
|
|
62
|
+
- `scripts/check-metadata.py`: gates the built artifacts — no direct references
|
|
63
|
+
in `Requires-Dist`, no dev-repo meta (`AGENTS.md`, `CLAUDE.md`, `.mappa/`,
|
|
64
|
+
`.wiki/`, `.tasks/`, `.pi/`) inside the wheel or the sdist. It runs in CI and
|
|
65
|
+
again in the release job, on the exact artifacts about to be uploaded.
|
|
66
|
+
- A `build` job in `ci.yml`: sdist + wheel + `twine check` + the metadata gate on
|
|
67
|
+
every push. A packaging mistake now costs a red run instead of a version
|
|
68
|
+
number.
|
|
69
|
+
- The sdist target excludes the dev-repo meta (`AGENTS.md`, `CLAUDE.md`,
|
|
70
|
+
`.mappa/`, `.mappa-manifest.json`, `.pi/`, `.wiki/`, `.tasks/`). The curated
|
|
71
|
+
pub tree already drops those files, but a build run in the *dev* tree picked
|
|
72
|
+
them up — dev's `.gitignore` keeps them on purpose — so `python -m build` from
|
|
73
|
+
a dev checkout put a canon snapshot into the sdist. The new gate found this on
|
|
74
|
+
its first run.
|
|
75
|
+
|
|
76
|
+
## [0.23.0] — 2026-09-13
|
|
77
|
+
|
|
78
|
+
### Changed
|
|
79
|
+
|
|
80
|
+
- **The distribution is `yt-tools-cli`.** PyPI refuses `yt-tools`: the name folds
|
|
81
|
+
into the same similarity class as the existing `yttools`, so the upload is
|
|
82
|
+
rejected at registration. The project, repository, plugin and every console
|
|
83
|
+
command stay `yt-tools`, and the import name stays `yt_tools` — only what
|
|
84
|
+
`pip`/`pipx` resolve changed.
|
|
85
|
+
- Every install hint now names the distribution (`pipx inject yt-tools-cli …`,
|
|
86
|
+
`pip install 'yt-tools-cli[extra]'`), and `doctor` builds its `next_step` from
|
|
87
|
+
the same constant as the refusals instead of a second hardcoded copy that would
|
|
88
|
+
have drifted out of sync.
|
|
89
|
+
|
|
90
|
+
### Added
|
|
91
|
+
|
|
92
|
+
- `scripts/publish-check.py`: verifies that a release actually landed on PyPI.
|
|
93
|
+
"Never landed", "version drift" and "incomplete artifacts" are reported as
|
|
94
|
+
three different failures with three different fixes.
|
|
95
|
+
- `.github/workflows/release.yml`: tag → build → PyPI by trusted publishing (OIDC,
|
|
96
|
+
no token on disk), with `publish-check` as the final job — a green build is not
|
|
97
|
+
a published release.
|
|
98
|
+
|
|
99
|
+
## [0.22.1] — 2026-09-13
|
|
100
|
+
|
|
101
|
+
### Fixed
|
|
102
|
+
|
|
103
|
+
- `scripts/check-pypi-name.py`: documented the staleness of its own input. The
|
|
104
|
+
names come from the simple index, which is CDN-cached, so a project created
|
|
105
|
+
minutes ago can still read as "available" — the verdict is a pre-flight, not a
|
|
106
|
+
report on the last hour. Found live, on the day `yt-tools-cli` was registered.
|
|
107
|
+
|
|
108
|
+
## [0.21.0] — 2026-09-13
|
|
109
|
+
|
|
110
|
+
### Added
|
|
111
|
+
|
|
112
|
+
- PyPI name pre-flight (`scripts/check-pypi-name.py`) reproducing warehouse's
|
|
113
|
+
`ultranormalize_name` similarity rule against the live index.
|
|
114
|
+
|
|
115
|
+
## [0.20.0] — 2026-09-13
|
|
116
|
+
|
|
117
|
+
### Added
|
|
118
|
+
|
|
119
|
+
- `scripts/check-core-install.sh` — the install contract (AC4/AC5) as a runnable
|
|
120
|
+
gate for a clean `python:3.12-slim`: core install only, then again with a real
|
|
121
|
+
static `ffmpeg`; asserts `can_proceed`/`next_step`/exit code on both sides and
|
|
122
|
+
that `warn` and `missing` stay distinguishable in one `--json` payload. Blocks A
|
|
123
|
+
and B expect opposite exit codes in one run, so it cannot pass vacuously.
|
|
124
|
+
|
|
125
|
+
## [0.19.1] — 2026-09-13
|
|
126
|
+
|
|
127
|
+
### Fixed
|
|
128
|
+
|
|
129
|
+
- `yt-tools cache list` / `cache prune` on an unreadable cache: named cause and a
|
|
130
|
+
non-zero exit instead of a traceback (the helper stays strict; the CLI explains).
|
|
131
|
+
- `yt-tools cache list` no longer presents a lower-bound size as an exact total —
|
|
132
|
+
both the entry and the total line carry the qualifier.
|
|
133
|
+
- `yt-tools doctor`: a dangling symlink in place of `yt-cache` (or of one of its
|
|
134
|
+
ancestors) is a `warn` with the reason, not an `ok`.
|
|
135
|
+
|
|
136
|
+
## [0.19.0] — 2026-09-13
|
|
137
|
+
|
|
138
|
+
### Added
|
|
139
|
+
|
|
140
|
+
- Public version reader: `yt_tools.__version__` is read from the installed
|
|
141
|
+
distribution metadata (falling back to `pyproject.toml` in a checkout), resolved
|
|
142
|
+
lazily — the last hand-maintained version source is gone.
|
|
143
|
+
|
|
144
|
+
### Fixed
|
|
145
|
+
|
|
146
|
+
- Coverage gaps found in review around the version reader.
|
|
147
|
+
|
|
148
|
+
## [0.18.2] — 2026-09-13
|
|
149
|
+
|
|
150
|
+
### Fixed
|
|
151
|
+
|
|
152
|
+
- `doctor` and `cache list` survive paths that are not representable in a cp1251
|
|
153
|
+
console (the Windows default) — output paths are data, not decoration.
|
|
154
|
+
|
|
155
|
+
## [0.18.1] — 2026-09-13
|
|
156
|
+
|
|
157
|
+
### Fixed
|
|
158
|
+
|
|
159
|
+
- `doctor`: an unreadable cache is a `warn` with the reason instead of a crash, and
|
|
160
|
+
a size that could only be partially counted says so ("lower bound").
|
|
161
|
+
- `doctor --base` pointing at a file (or at a path whose ancestor is a file) is a
|
|
162
|
+
`warn`, not a silent `ok`.
|
|
163
|
+
- Writability is decided by an actual write probe, not `os.access` (which reads the
|
|
164
|
+
DOS read-only attribute on Windows and made the check dead on the primary platform).
|
|
165
|
+
|
|
166
|
+
## [0.18.0] — 2026-09-13
|
|
167
|
+
|
|
168
|
+
### Added
|
|
169
|
+
|
|
170
|
+
- Portable skill: harness-neutral install and usage instructions, plus the `doctor`
|
|
171
|
+
preflight as the documented first step.
|
|
172
|
+
|
|
173
|
+
## [0.17.0] — 2026-09-12
|
|
174
|
+
|
|
175
|
+
### Added
|
|
176
|
+
|
|
177
|
+
- `yt-tools doctor` (`--json`): environment preflight with per-check `status`,
|
|
178
|
+
report-level `can_proceed` and `next_step`. `warn` never blocks; a missing
|
|
179
|
+
required binary (`yt-dlp`, `ffmpeg`) does. Nothing is installed or mutated.
|
|
180
|
+
|
|
181
|
+
## [0.16.0] — 2026-09-12
|
|
182
|
+
|
|
183
|
+
### Added
|
|
184
|
+
|
|
185
|
+
- Single source of version truth: `pyproject.toml`, with `scripts/sync-version.py`
|
|
186
|
+
writing the derived manifests and a guard test failing on divergence.
|
|
187
|
+
|
|
188
|
+
## [0.15.1] — 2026-09-12
|
|
189
|
+
|
|
190
|
+
### Fixed
|
|
191
|
+
|
|
192
|
+
- Extra detection by import probe rather than a package-metadata guess; degradation
|
|
193
|
+
announced with its own wording instead of a refusal.
|
|
194
|
+
|
|
195
|
+
## [0.15.0] — 2026-09-12
|
|
196
|
+
|
|
197
|
+
### Changed
|
|
198
|
+
|
|
199
|
+
- A flow whose optional stack is missing refuses with the exact install command
|
|
200
|
+
instead of raising `ImportError`.
|
|
201
|
+
|
|
202
|
+
## [0.14.0] — 2026-09-12
|
|
203
|
+
|
|
204
|
+
### Changed
|
|
205
|
+
|
|
206
|
+
- Light core: `pip install yt-tools` pulls `youtube-transcript-api` and `yt-dlp`
|
|
207
|
+
only. The heavy stacks moved into `[frames]`, `[audio]` and `[ocr]` extras.
|
|
208
|
+
|
|
209
|
+
## [0.13.1] — 2026-09-12
|
|
210
|
+
|
|
211
|
+
### Fixed
|
|
212
|
+
|
|
213
|
+
- Findings from the umbrella review of the frame-budget cluster.
|
|
214
|
+
|
|
215
|
+
## [0.13.0] — 2026-09-12
|
|
216
|
+
|
|
217
|
+
### Added
|
|
218
|
+
|
|
219
|
+
- A video without subtitles refuses with a named reason instead of an empty file;
|
|
220
|
+
`yt-watch` gained a frames-only mode.
|
|
221
|
+
|
|
222
|
+
## [0.12.0] — 2026-09-12
|
|
223
|
+
|
|
224
|
+
### Added
|
|
225
|
+
|
|
226
|
+
- Frame budget recorded in the `watch.md` artifact.
|
|
227
|
+
|
|
228
|
+
## [0.11.0] — 2026-09-11
|
|
229
|
+
|
|
230
|
+
### Fixed
|
|
231
|
+
|
|
232
|
+
- Unique frame filenames within the same second.
|
|
233
|
+
|
|
234
|
+
## [0.10.0] — 2026-09-11
|
|
235
|
+
|
|
236
|
+
### Added
|
|
237
|
+
|
|
238
|
+
- Near-duplicate frame dedup: the budget is spent on distinct frames.
|
|
239
|
+
|
|
240
|
+
## [0.9.0] — 2026-09-11
|
|
241
|
+
|
|
242
|
+
### Added
|
|
243
|
+
|
|
244
|
+
- Uniform-sampling fallback when scene detection finds nothing (a static video no
|
|
245
|
+
longer yields a single frame).
|
|
246
|
+
|
|
247
|
+
## [0.8.0] — 2026-09-11
|
|
248
|
+
|
|
249
|
+
### Added
|
|
250
|
+
|
|
251
|
+
- `--max-frames` ceiling: a video cannot hand back an arbitrary number of frames.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for looking. yt-tools is a small, opinionated toolkit: nine stateless CLIs
|
|
4
|
+
for agent-driven YouTube watching. The rules below exist to keep it that way.
|
|
5
|
+
|
|
6
|
+
## Getting set up
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
git clone https://github.com/kzntsv-dev/yt-tools.git
|
|
10
|
+
cd yt-tools
|
|
11
|
+
pip install -e ".[full,test]" # [full] = frames + audio stacks; [ocr] is separate
|
|
12
|
+
pytest -q
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`ffmpeg` and `yt-dlp` are external binaries the tools shell out to; `yt-tools
|
|
16
|
+
doctor` reports what is present and the exact command for what is not.
|
|
17
|
+
|
|
18
|
+
Two gates are worth knowing before you push:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pytest -q # unit + CLI smoke (network is mocked)
|
|
22
|
+
bash scripts/check-core-install.sh # needs docker: the install contract, end to end
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## What a change should look like
|
|
26
|
+
|
|
27
|
+
- **Test first.** A behaviour change comes with a test that fails without it. If
|
|
28
|
+
you cannot make the test fail on the current code, it is not testing the change.
|
|
29
|
+
A test that cannot fail (a "guard") is welcome, but say so in its docstring.
|
|
30
|
+
- **Explain the refusal.** Absence of an optional dependency is a message with the
|
|
31
|
+
exact command, never a traceback. The same goes for a broken environment: report
|
|
32
|
+
it and exit non-zero.
|
|
33
|
+
- **Say what you know and what you do not.** If a number can only be partially
|
|
34
|
+
computed, qualify it — an undercount presented as an exact figure is the bug
|
|
35
|
+
class this project has already been bitten by.
|
|
36
|
+
- **Keep the core light.** Anything heavy belongs in an extra. `pip install
|
|
37
|
+
yt-tools` must stay a seconds-long install.
|
|
38
|
+
- **Add an entry** to `CHANGELOG.md` under `[Unreleased]`, and bump `version` in
|
|
39
|
+
`pyproject.toml` (see below).
|
|
40
|
+
|
|
41
|
+
## Style
|
|
42
|
+
|
|
43
|
+
- Python 3.10+ syntax, `from __future__ import annotations` at the top.
|
|
44
|
+
- Comments and docstrings explain *why* — ideally with the failure that motivated
|
|
45
|
+
them. "What" is the code's job.
|
|
46
|
+
- Human-facing output templates stay ASCII: the console may be cp1251 on Windows.
|
|
47
|
+
- Keep output parseable: `--json` where a machine reads it, stable wording where a
|
|
48
|
+
person does.
|
|
49
|
+
|
|
50
|
+
## Releases
|
|
51
|
+
|
|
52
|
+
The version lives in exactly one place — `pyproject.toml`. The derived files are
|
|
53
|
+
written by a script, never by hand:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# 1. bump `version` in pyproject.toml
|
|
57
|
+
python scripts/sync-version.py # plugin.json + skill frontmatter
|
|
58
|
+
python scripts/sync-version.py --check # what the guard test runs
|
|
59
|
+
# 2. add the CHANGELOG entry, commit, push
|
|
60
|
+
git commit -m "feat(scope): what changed (vX.Y.Z)"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`tests/test_version.py` fails when the sources disagree, so a half-finished bump
|
|
64
|
+
cannot ship.
|
|
65
|
+
|
|
66
|
+
## Reporting a bug
|
|
67
|
+
|
|
68
|
+
Include what you ran, what you expected, what happened (the exact message), your
|
|
69
|
+
platform, and the output of `yt-tools doctor`. Issues that reproduce on a bare
|
|
70
|
+
`pip install yt-tools` are the most valuable ones.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Victor Kuznetsov
|
|
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.
|