annextube 0.14.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.
- annextube-0.14.0/.autorc +83 -0
- annextube-0.14.0/.gitignore +119 -0
- annextube-0.14.0/.jscpd.json +18 -0
- annextube-0.14.0/CHANGELOG.md +359 -0
- annextube-0.14.0/CLAUDE.md +230 -0
- annextube-0.14.0/CONTRIBUTING.md +200 -0
- annextube-0.14.0/LICENSE +20 -0
- annextube-0.14.0/PKG-INFO +220 -0
- annextube-0.14.0/README.md +132 -0
- annextube-0.14.0/annextube/__init__.py +0 -0
- annextube-0.14.0/annextube/__main__.py +6 -0
- annextube-0.14.0/annextube/_version.py +24 -0
- annextube-0.14.0/annextube/cli/__init__.py +0 -0
- annextube-0.14.0/annextube/cli/__main__.py +113 -0
- annextube-0.14.0/annextube/cli/aggregate.py +268 -0
- annextube-0.14.0/annextube/cli/backup.py +499 -0
- annextube-0.14.0/annextube/cli/build_search_index.py +90 -0
- annextube-0.14.0/annextube/cli/check.py +258 -0
- annextube-0.14.0/annextube/cli/collection.py +138 -0
- annextube-0.14.0/annextube/cli/completion.py +63 -0
- annextube-0.14.0/annextube/cli/curate_captions.py +449 -0
- annextube-0.14.0/annextube/cli/embed_config.py +116 -0
- annextube-0.14.0/annextube/cli/export.py +116 -0
- annextube-0.14.0/annextube/cli/generate_web.py +305 -0
- annextube-0.14.0/annextube/cli/info.py +130 -0
- annextube-0.14.0/annextube/cli/init.py +175 -0
- annextube-0.14.0/annextube/cli/init_user_config.py +51 -0
- annextube-0.14.0/annextube/cli/prepare_ghpages.py +534 -0
- annextube-0.14.0/annextube/cli/serve.py +290 -0
- annextube-0.14.0/annextube/cli/unannex.py +75 -0
- annextube-0.14.0/annextube/lib/__init__.py +0 -0
- annextube-0.14.0/annextube/lib/annex_utils.py +69 -0
- annextube-0.14.0/annextube/lib/archive_discovery.py +152 -0
- annextube-0.14.0/annextube/lib/cli_options.py +48 -0
- annextube-0.14.0/annextube/lib/config.py +900 -0
- annextube-0.14.0/annextube/lib/date_utils.py +103 -0
- annextube-0.14.0/annextube/lib/error_utils.py +31 -0
- annextube-0.14.0/annextube/lib/file_utils.py +84 -0
- annextube-0.14.0/annextube/lib/logging_config.py +137 -0
- annextube-0.14.0/annextube/lib/process_semaphore.py +142 -0
- annextube-0.14.0/annextube/lib/quota_manager.py +223 -0
- annextube-0.14.0/annextube/lib/range_server.py +146 -0
- annextube-0.14.0/annextube/lib/tsv_utils.py +111 -0
- annextube-0.14.0/annextube/lib/ytdlp_ratelimit.py +232 -0
- annextube-0.14.0/annextube/models/__init__.py +7 -0
- annextube-0.14.0/annextube/models/author.py +50 -0
- annextube-0.14.0/annextube/models/channel.py +75 -0
- annextube-0.14.0/annextube/models/curation.py +143 -0
- annextube-0.14.0/annextube/models/playlist.py +51 -0
- annextube-0.14.0/annextube/models/video.py +195 -0
- annextube-0.14.0/annextube/schema/extra_metadata.yaml +130 -0
- annextube-0.14.0/annextube/schema/models.json +691 -0
- annextube-0.14.0/annextube/services/__init__.py +0 -0
- annextube-0.14.0/annextube/services/archiver.py +2221 -0
- annextube-0.14.0/annextube/services/authors.py +209 -0
- annextube-0.14.0/annextube/services/caption_curator.py +837 -0
- annextube-0.14.0/annextube/services/collection.py +356 -0
- annextube-0.14.0/annextube/services/export.py +783 -0
- annextube-0.14.0/annextube/services/git_annex.py +845 -0
- annextube-0.14.0/annextube/services/llm_corrector.py +219 -0
- annextube-0.14.0/annextube/services/search_index.py +835 -0
- annextube-0.14.0/annextube/services/tsv_reader.py +184 -0
- annextube-0.14.0/annextube/services/youtube.py +1734 -0
- annextube-0.14.0/annextube/services/youtube_api.py +899 -0
- annextube-0.14.0/hatch_build.py +75 -0
- annextube-0.14.0/pyproject.toml +227 -0
- annextube-0.14.0/tests/conftest.py +81 -0
- annextube-0.14.0/tests/contract/__init__.py +0 -0
- annextube-0.14.0/tests/contract/test_backup_json.py +242 -0
- annextube-0.14.0/tests/contract/test_collection_cli.py +238 -0
- annextube-0.14.0/tests/e2e/README.md +289 -0
- annextube-0.14.0/tests/e2e/test_collection_e2e.py +277 -0
- annextube-0.14.0/tests/e2e/test_multi_channel.py +321 -0
- annextube-0.14.0/tests/e2e/test_web_ui.py +241 -0
- annextube-0.14.0/tests/e2e/verify_archive.py +182 -0
- annextube-0.14.0/tests/fixtures/sample_glossary.yaml +37 -0
- annextube-0.14.0/tests/fixtures/sample_karaoke.vtt +33 -0
- annextube-0.14.0/tests/integration/test_api_enhanced_metadata.py +483 -0
- annextube-0.14.0/tests/integration/test_checkpoint_commits.py +371 -0
- annextube-0.14.0/tests/integration/test_collection.py +308 -0
- annextube-0.14.0/tests/integration/test_comprehensive_backup.py +229 -0
- annextube-0.14.0/tests/integration/test_e2e_backup_features.py +251 -0
- annextube-0.14.0/tests/integration/test_incremental_backup.py +145 -0
- annextube-0.14.0/tests/integration/test_new_video_components.py +120 -0
- annextube-0.14.0/tests/integration/test_no_timestamp_commits.py +183 -0
- annextube-0.14.0/tests/integration/test_search_index_build.py +177 -0
- annextube-0.14.0/tests/integration/test_update_annexed_files.py +144 -0
- annextube-0.14.0/tests/test_component_mode_bug.py +79 -0
- annextube-0.14.0/tests/test_date_filtering.py +108 -0
- annextube-0.14.0/tests/test_tsv_refactoring.py +392 -0
- annextube-0.14.0/tests/unit/test_annex_utils.py +105 -0
- annextube-0.14.0/tests/unit/test_archive_discovery.py +270 -0
- annextube-0.14.0/tests/unit/test_atomic_file_write.py +179 -0
- annextube-0.14.0/tests/unit/test_batch_api_optimization.py +222 -0
- annextube-0.14.0/tests/unit/test_caption_curator.py +729 -0
- annextube-0.14.0/tests/unit/test_collection_config.py +122 -0
- annextube-0.14.0/tests/unit/test_collection_service.py +94 -0
- annextube-0.14.0/tests/unit/test_completion.py +100 -0
- annextube-0.14.0/tests/unit/test_config_precedence.py +127 -0
- annextube-0.14.0/tests/unit/test_curation_config.py +132 -0
- annextube-0.14.0/tests/unit/test_datalad_init.py +79 -0
- annextube-0.14.0/tests/unit/test_deploy_frontend_staleness.py +85 -0
- annextube-0.14.0/tests/unit/test_embed_config.py +156 -0
- annextube-0.14.0/tests/unit/test_error_reporting.py +89 -0
- annextube-0.14.0/tests/unit/test_export_channel_json.py +417 -0
- annextube-0.14.0/tests/unit/test_export_descriptions.py +215 -0
- annextube-0.14.0/tests/unit/test_git_annex_channel_json_timestamps.py +250 -0
- annextube-0.14.0/tests/unit/test_git_annex_metadata.py +156 -0
- annextube-0.14.0/tests/unit/test_git_annex_timestamp_filter.py +188 -0
- annextube-0.14.0/tests/unit/test_hierarchical_video_paths.py +502 -0
- annextube-0.14.0/tests/unit/test_init.py +133 -0
- annextube-0.14.0/tests/unit/test_new_video_detection.py +87 -0
- annextube-0.14.0/tests/unit/test_playlist_model.py +83 -0
- annextube-0.14.0/tests/unit/test_playlist_symlinks.py +619 -0
- annextube-0.14.0/tests/unit/test_process_semaphore.py +115 -0
- annextube-0.14.0/tests/unit/test_quota_estimator.py +133 -0
- annextube-0.14.0/tests/unit/test_quota_manager.py +296 -0
- annextube-0.14.0/tests/unit/test_retroactive_curation.py +102 -0
- annextube-0.14.0/tests/unit/test_sdist_frontend.py +92 -0
- annextube-0.14.0/tests/unit/test_search_index.py +809 -0
- annextube-0.14.0/tests/unit/test_tsv_escaping.py +147 -0
- annextube-0.14.0/tests/unit/test_unavailable_video_filtering.py +771 -0
- annextube-0.14.0/tests/unit/test_video_model.py +90 -0
- annextube-0.14.0/tests/unit/test_youtube_api_client.py +428 -0
- annextube-0.14.0/tests/unit/test_youtube_api_quota_handling.py +344 -0
- annextube-0.14.0/tests/unit/test_youtube_service_playlist.py +220 -0
- annextube-0.14.0/tests/unit/test_ytdlp_ratelimit.py +224 -0
- annextube-0.14.0/tox.ini +149 -0
- annextube-0.14.0/web/assets/index.css +1 -0
- annextube-0.14.0/web/assets/index.js +17 -0
- annextube-0.14.0/web/index.html +14 -0
annextube-0.14.0/.autorc
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"baseBranch": "master",
|
|
3
|
+
"noVersionPrefix": false,
|
|
4
|
+
"plugins": [
|
|
5
|
+
"git-tag",
|
|
6
|
+
[
|
|
7
|
+
"exec",
|
|
8
|
+
{
|
|
9
|
+
"afterRelease": "python -m build && twine upload dist/*"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"released"
|
|
13
|
+
],
|
|
14
|
+
"labels": [
|
|
15
|
+
{
|
|
16
|
+
"name": "release-major",
|
|
17
|
+
"releaseType": "major",
|
|
18
|
+
"changelogTitle": "💥 Breaking Change",
|
|
19
|
+
"description": "Increment the major version when merged",
|
|
20
|
+
"color": "C5000B"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "release-minor",
|
|
24
|
+
"releaseType": "minor",
|
|
25
|
+
"changelogTitle": "🚀 Enhancement",
|
|
26
|
+
"description": "Increment the minor version when merged",
|
|
27
|
+
"color": "F1A60E"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "release-patch",
|
|
31
|
+
"releaseType": "patch",
|
|
32
|
+
"changelogTitle": "🐛 Bug Fix",
|
|
33
|
+
"description": "Increment the patch version when merged",
|
|
34
|
+
"color": "870048"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "release",
|
|
38
|
+
"releaseType": "release",
|
|
39
|
+
"description": "Create a release when this PR is merged",
|
|
40
|
+
"color": "16a34a"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "skip-release",
|
|
44
|
+
"releaseType": "skip",
|
|
45
|
+
"description": "Preserve the current version when merged",
|
|
46
|
+
"color": "bf5416"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "internal",
|
|
50
|
+
"releaseType": "none",
|
|
51
|
+
"changelogTitle": "🏠 Internal",
|
|
52
|
+
"description": "Changes only affect the internal API",
|
|
53
|
+
"color": "696969"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "documentation",
|
|
57
|
+
"releaseType": "none",
|
|
58
|
+
"changelogTitle": "📝 Documentation",
|
|
59
|
+
"description": "Changes only affect the documentation",
|
|
60
|
+
"color": "cfd3d7"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "tests",
|
|
64
|
+
"releaseType": "none",
|
|
65
|
+
"changelogTitle": "🧪 Tests",
|
|
66
|
+
"description": "Add or improve existing tests",
|
|
67
|
+
"color": "e4e669"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "performance",
|
|
71
|
+
"releaseType": "patch",
|
|
72
|
+
"changelogTitle": "🏎 Performance",
|
|
73
|
+
"description": "Improve performance of an existing feature",
|
|
74
|
+
"color": "f4b2d8"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"name": "released",
|
|
78
|
+
"releaseType": "none",
|
|
79
|
+
"description": "This PR has been released",
|
|
80
|
+
"color": "84cc16"
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib64/
|
|
14
|
+
parts/
|
|
15
|
+
sdist/
|
|
16
|
+
var/
|
|
17
|
+
wheels/
|
|
18
|
+
pip-wheel-metadata/
|
|
19
|
+
share/python-wheels/
|
|
20
|
+
*.egg-info/
|
|
21
|
+
.installed.cfg
|
|
22
|
+
*.egg
|
|
23
|
+
MANIFEST
|
|
24
|
+
|
|
25
|
+
# Virtual environments
|
|
26
|
+
.venv/
|
|
27
|
+
venv/
|
|
28
|
+
ENV/
|
|
29
|
+
env/
|
|
30
|
+
.virtualenv
|
|
31
|
+
uv.lock
|
|
32
|
+
|
|
33
|
+
# Testing
|
|
34
|
+
.tox/
|
|
35
|
+
.nox/
|
|
36
|
+
.coverage
|
|
37
|
+
.coverage.*
|
|
38
|
+
.cache
|
|
39
|
+
nosetests.xml
|
|
40
|
+
coverage.xml
|
|
41
|
+
*.cover
|
|
42
|
+
*.log
|
|
43
|
+
.pytest_cache/
|
|
44
|
+
htmlcov/
|
|
45
|
+
|
|
46
|
+
# Type checking
|
|
47
|
+
.mypy_cache/
|
|
48
|
+
.dmypy.json
|
|
49
|
+
dmypy.json
|
|
50
|
+
.pyre/
|
|
51
|
+
.pytype/
|
|
52
|
+
|
|
53
|
+
# IDEs
|
|
54
|
+
.vscode/
|
|
55
|
+
.idea/
|
|
56
|
+
.vim/
|
|
57
|
+
.viminfo
|
|
58
|
+
*.swp
|
|
59
|
+
*.swo
|
|
60
|
+
*~
|
|
61
|
+
.DS_Store
|
|
62
|
+
Thumbs.db
|
|
63
|
+
|
|
64
|
+
# Project specific
|
|
65
|
+
.annextube/
|
|
66
|
+
test-archive/
|
|
67
|
+
test-archives/
|
|
68
|
+
*.tmp
|
|
69
|
+
|
|
70
|
+
# Node.js (frontend)
|
|
71
|
+
node_modules/
|
|
72
|
+
.npm/
|
|
73
|
+
npm-debug.log*
|
|
74
|
+
yarn-debug.log*
|
|
75
|
+
yarn-error.log*
|
|
76
|
+
.lesshst
|
|
77
|
+
|
|
78
|
+
# Build artifacts
|
|
79
|
+
*.min.js
|
|
80
|
+
*.min.css
|
|
81
|
+
web/
|
|
82
|
+
demo/
|
|
83
|
+
frontend/dist/
|
|
84
|
+
frontend/build/
|
|
85
|
+
pagefind/
|
|
86
|
+
|
|
87
|
+
# Environment files
|
|
88
|
+
.env
|
|
89
|
+
.env.local
|
|
90
|
+
.env.*.local
|
|
91
|
+
*.key
|
|
92
|
+
*.pem
|
|
93
|
+
credentials.json
|
|
94
|
+
|
|
95
|
+
# Documentation
|
|
96
|
+
docs/_build/
|
|
97
|
+
docs/.hugo_build.lock
|
|
98
|
+
|
|
99
|
+
# Shell history and local config
|
|
100
|
+
.bash_history
|
|
101
|
+
.config/ # User config created during testing
|
|
102
|
+
.anaconda/
|
|
103
|
+
.conda/
|
|
104
|
+
.claude/settings.local.json
|
|
105
|
+
annextube/_version.py
|
|
106
|
+
.deno
|
|
107
|
+
.local
|
|
108
|
+
.worktrees
|
|
109
|
+
.config
|
|
110
|
+
.ssh
|
|
111
|
+
|
|
112
|
+
# Various files claude likes to create
|
|
113
|
+
CHANGES_SUMMARY.md
|
|
114
|
+
DEMO_SETUP.md
|
|
115
|
+
EXAMPLE_UNAVAILABLE_FILTERING.md
|
|
116
|
+
|
|
117
|
+
# no duct logs here -- only for tests etc
|
|
118
|
+
.duct
|
|
119
|
+
.claude/worktrees
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"threshold": 0,
|
|
3
|
+
"reporters": ["console"],
|
|
4
|
+
"ignore": [
|
|
5
|
+
"**/node_modules/**",
|
|
6
|
+
"**/.git/**",
|
|
7
|
+
"**/dist/**",
|
|
8
|
+
"**/.tox/**",
|
|
9
|
+
"**/.venv/**",
|
|
10
|
+
"**/__pycache__/**",
|
|
11
|
+
"**/web/**",
|
|
12
|
+
"**/.specify/**",
|
|
13
|
+
"**/specs/**",
|
|
14
|
+
"**/tools/**"
|
|
15
|
+
],
|
|
16
|
+
"minTokens": 50,
|
|
17
|
+
"minLines": 5
|
|
18
|
+
}
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# v0.14.0 (Fri Sep 04 2026)
|
|
2
|
+
|
|
3
|
+
#### 🚀 Enhancement
|
|
4
|
+
|
|
5
|
+
- Searchable video descriptions + Metadata/Full search modes (FR-042d–g) [#6](https://github.com/con/annextube/pull/6) ([@claude](https://github.com/claude) [@yarikoptic](https://github.com/yarikoptic) [@yarikoptic-gitmate](https://github.com/yarikoptic-gitmate))
|
|
6
|
+
- Flag approximate caption search matches and reorder results [#7](https://github.com/con/annextube/pull/7) ([@claude](https://github.com/claude) [@yarikoptic-gitmate](https://github.com/yarikoptic-gitmate))
|
|
7
|
+
|
|
8
|
+
#### ⚠️ Pushed to `master`
|
|
9
|
+
|
|
10
|
+
- fix(release): use releaseType "none" for the "released" label ([@yarikoptic](https://github.com/yarikoptic))
|
|
11
|
+
|
|
12
|
+
#### 🏠 Internal
|
|
13
|
+
|
|
14
|
+
- feat(release): introduce intuit/auto for automated releases [#8](https://github.com/con/annextube/pull/8) ([@yarikoptic](https://github.com/yarikoptic))
|
|
15
|
+
|
|
16
|
+
#### Authors: 3
|
|
17
|
+
|
|
18
|
+
- Claude ([@claude](https://github.com/claude))
|
|
19
|
+
- GitMate for @yarikoptic ([@yarikoptic-gitmate](https://github.com/yarikoptic-gitmate))
|
|
20
|
+
- Yaroslav Halchenko ([@yarikoptic](https://github.com/yarikoptic))
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# Changelog
|
|
25
|
+
|
|
26
|
+
<!-- Entries from v0.14.0 onward are auto-generated by intuit/auto. -->
|
|
27
|
+
<!-- Entries prior to v0.14.0 use Keep a Changelog format. -->
|
|
28
|
+
|
|
29
|
+
## [0.13.0] - 2026-07-13
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **Multi-channel collection management (feature 003)**: DataLad superdataset workflow for archives that aggregate multiple channels — `annextube collection add`, `annextube aggregate`, breadcrumb navigation in the web UI, and the corresponding contract / integration / E2E test suites. Ships alongside a spec artifact under `.specify/specs/003-multi-channel-collections/`
|
|
34
|
+
- **Retroactive caption curation during backup** (FR-062a): backups can now run the caption curation pipeline over existing archived videos, not just newly-fetched ones
|
|
35
|
+
- **`annextube completion` command** (FR-057i, T141): outputs shell completion scripts for bash, zsh, and fish via Click's `ShellComplete.source()`; auto-detects the current shell from `$SHELL`
|
|
36
|
+
- **MKV video playback: browser-specific error messages**: the web player now explains which browsers can natively decode MKV and links users to workarounds. Feature spec `.specify/specs/002-mkv-video-playback/`
|
|
37
|
+
- **GitHub Actions test workflow**: tox-based Python matrix (3.10 – 3.14) plus lint / type / coverage jobs, running on every push and PR
|
|
38
|
+
- **JSON backup output (T030) + batch API optimization (T039)**: completes remaining MVP gaps identified in `speckit.analyze`
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- **yt-dlp playlist pagination truncation**: older yt-dlp releases silently truncated large YouTube playlists at ~100 entries even though `playlist_count` reported the true size, causing videos to appear-and-disappear across runs. Fixed upstream in yt-dlp/yt-dlp#16948; minimum requirement bumped to `yt-dlp>=2026.07.04`. Layered defence in the archive too: `Archiver._save_playlist_metadata` refuses to persist truncated lists, and when a YouTube Data API key is configured `YouTubeService.get_playlist_metadata` cross-checks against `playlistItems.list` and prefers the API's authoritative list
|
|
43
|
+
- **YouTube API robustness**: HTTP error bodies decoded with `errors='replace'`; mid-pagination quota-exceeded events resume from the current `pageToken` instead of restarting from page 1 (applies to `get_playlist_video_ids` and `fetch_comments`)
|
|
44
|
+
- **`annextube init` on an existing git-annex repo**: skip repo init when the target is already a git-annex working tree, and configure `annex.security.allowed-*` policies so the reused repo doesn't drop content
|
|
45
|
+
- **Single-channel archive detection requires `.annextube/config.toml`**: previously a bare git repo could be misdetected as a single-channel archive
|
|
46
|
+
- **Thumbnail download failures downgraded to warnings**: no longer aborts a backup
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
|
|
50
|
+
- **Zero-tolerance code duplication**: dedicated jscpd tox env with threshold 0 %; the entire codebase now reports 0 clones after helper extraction (batch prefetch, video-processing loop, symlink writer, unavailable-video recorder, playlist-tab-entry parser, atomic-write prep, shared `--output-dir` Click decorator)
|
|
51
|
+
- **Constitution amended to v1.5.0**: adds Principle XIII "DataLad-Native Operations"
|
|
52
|
+
|
|
53
|
+
## [0.12.0] - 2026-03-11
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
|
|
57
|
+
- **`annextube init` modular flags**: `--curation`, `--search`, `--enable-all` for selective feature initialization
|
|
58
|
+
- **`[full]` extra**: `pip install annextube[full]` installs all optional dependencies
|
|
59
|
+
- **Auto-build search index after backup**: Pagefind caption index is rebuilt automatically when captions change
|
|
60
|
+
- **Real-pagefind integration tests**: 7 tests exercise the actual pagefind binary with 30s timeout to catch IPC stalls
|
|
61
|
+
- **WCAG 2.1 AA accessibility tests**: Automated contrast-ratio and a11y checks for the web frontend
|
|
62
|
+
- **Zero-tolerance code duplication**: jscpd enforced at threshold 0 across the codebase
|
|
63
|
+
|
|
64
|
+
### Fixed
|
|
65
|
+
|
|
66
|
+
- **Pagefind IPC deadlock on DataLad subdatasets**: The pagefind binary hangs when its output directory contains git-annex symlinks (read-only targets) from a previous build. Fixed by writing to a clean temp directory, then syncing into the subdataset
|
|
67
|
+
- **Pagefind IPC pipe interlocking**: Separate stderr from stdout, bypass the upstream library's fragile polling task, use direct IPC with 300s timeout for WriteFiles
|
|
68
|
+
- **Color contrast violation**: Fixed insufficient contrast ratio in frontend CSS
|
|
69
|
+
|
|
70
|
+
### Changed
|
|
71
|
+
|
|
72
|
+
- **DataLad is now a core dependency**: Removed plain git submodule fallback; all subdataset operations use DataLad exclusively
|
|
73
|
+
- **DataLad cfg_text2git for pagefind subdataset**: Use DataLad's built-in text2git configuration instead of manual .gitattributes
|
|
74
|
+
- **yt-dlp[default] co-installs challenge solver**: No longer need separate `yt-dlp-youtube-oauth2` or manual solver setup
|
|
75
|
+
- **Consolidate scripts/ into tools/**: All helper scripts live in `tools/`, tox.ini calls them directly
|
|
76
|
+
- **Spec harmonization**: Aligned specification artifacts with implementation reality
|
|
77
|
+
|
|
78
|
+
## [0.11.0] - 2026-03-04
|
|
79
|
+
|
|
80
|
+
### Added
|
|
81
|
+
|
|
82
|
+
- **Full-text caption search via Pagefind**: Search across all video captions with highlighted results and click-to-seek
|
|
83
|
+
- **`build-search-index` CLI command**: Standalone pagefind index generation
|
|
84
|
+
- **DataLad subdataset management for pagefind index**: Automatic subdataset creation with cfg_text2git
|
|
85
|
+
- **Caption search UX polish**: Improved search result display and git submodule for pagefind frontend assets
|
|
86
|
+
|
|
87
|
+
### Fixed
|
|
88
|
+
|
|
89
|
+
- **Duplicate pagefind/ output at archive root**: Index files now go only to `web/pagefind/`
|
|
90
|
+
- **Pagefind 100ms polling sleep**: Removed upstream library's polling delay causing ~140x slowdown
|
|
91
|
+
- **Curated caption writes on annexed files**: Use AtomicFileWriter to handle symlink-to-readonly targets
|
|
92
|
+
- **Pagefind URL resolution**: Fixed incorrect paths in subdirectory deployments
|
|
93
|
+
|
|
94
|
+
## [0.10.0] - 2026-03-02
|
|
95
|
+
|
|
96
|
+
### Added
|
|
97
|
+
|
|
98
|
+
- **Aggregated error reporting**: Record all errors during backup and fail at end with summary instead of aborting on first error
|
|
99
|
+
|
|
100
|
+
### Fixed
|
|
101
|
+
|
|
102
|
+
- **metadata.json writes on annexed files**: Use UTF-8 encoding and handle annexed file targets correctly
|
|
103
|
+
- **git diff quoting for non-ASCII paths**: Fixed diff parsing for filenames with special characters
|
|
104
|
+
- **Unavailable video handling**: Skip downloads for known-unavailable videos in incremental channel backup
|
|
105
|
+
- **Thumbnail re-download**: Skip unless in force mode
|
|
106
|
+
- **TSV commit failure**: Target specific files and deduplicate commit logic
|
|
107
|
+
- **Playlist-exclusive detection**: Include existing and unavailable video IDs
|
|
108
|
+
|
|
109
|
+
### Changed
|
|
110
|
+
|
|
111
|
+
- **Stop writing volatile timestamps to channel.json**: Removed last_sync/fetched_at fields that caused unnecessary commits
|
|
112
|
+
|
|
113
|
+
## [0.9.0] - 2026-02-18
|
|
114
|
+
|
|
115
|
+
### Added
|
|
116
|
+
|
|
117
|
+
- **`embed-config` command**: Propagate shared TOML settings (e.g. `[curation]` glossary) from a super-dataset config into subdataset configs with comment-preserving deep merge. Supports `--existing keep` (default) and `--existing update` modes. Skips `[[sources]]` (per-subdataset)
|
|
118
|
+
- **Caption curation design spec**: Planning document for the curation pipeline
|
|
119
|
+
- **`[curation]` section in config template**: Generated configs now include documented curation settings (glossary, fuzzy matching, LLM, audio alignment)
|
|
120
|
+
- **Glossary discovery with parent collation**: `glossary_path` + `glossary_collate_parents` in `[curation]` config for multi-channel setups — walk up parent dirs and merge all glossaries found
|
|
121
|
+
- **Caption curation pipeline**: 8-stage ASR correction (`curate-captions` command) — glossary regex, LLM corrections, fuzzy matching, filler removal, ASR artifact fixes, sentence segmentation, cue chunking, timestamp restoration
|
|
122
|
+
- **Clone command panel**: Web UI header button to clone the archive repository
|
|
123
|
+
- **`tomlkit` dependency**: Comment-preserving TOML editing for `embed-config`
|
|
124
|
+
- **`types-PyYAML` dev dependency**: Fix mypy type checking for yaml imports
|
|
125
|
+
|
|
126
|
+
### Fixed
|
|
127
|
+
|
|
128
|
+
- **`curate-captions` ignoring archive config for VIDEO_PATH**: Direct video directory mode was creating bare `CurationConfig()` defaults instead of loading `.annextube/config.toml`, silently ignoring `glossary_path` and other `[curation]` settings
|
|
129
|
+
- **Transcript language selector reverting**: Fixed CaptionBrowser resetting user language picks on reactive updates
|
|
130
|
+
- **Clone command UI**: Fixed reactive updates, tab switching, and inline layout
|
|
131
|
+
- **Curated captions not default in transcript browser**: CaptionBrowser now auto-selects the curated variant (e.g. `en-curated`) over the base language; `en-curated` displays as "EN (curated)"
|
|
132
|
+
|
|
133
|
+
### Changed
|
|
134
|
+
|
|
135
|
+
- **Skip already-archived videos during playlist backup**: Incremental playlist backup no longer re-processes existing videos
|
|
136
|
+
|
|
137
|
+
## [0.8.0] - 2026-02-16
|
|
138
|
+
|
|
139
|
+
### Added
|
|
140
|
+
|
|
141
|
+
- **yt-dlp rate-limit detection and concurrency limiting**: Detects YouTube 429/rate-limit responses and retries with exponential backoff. Cross-process concurrency limiting via file locks prevents parallel yt-dlp calls from triggering rate limits
|
|
142
|
+
- **`tox -e sdist-check`**: Automated pre-release verification — builds sdist, installs in clean venv, verifies built frontend is included and `generate-web` works
|
|
143
|
+
- **`tox -e full`**: Run all non-network tests with all optional deps (including playwright)
|
|
144
|
+
- **Pre-release sdist verification checklist**: Documented manual tarball inspection steps
|
|
145
|
+
|
|
146
|
+
### Fixed
|
|
147
|
+
|
|
148
|
+
- **Catastrophically slow sdist build**: `skip-excluded-dirs = true` prevents hatchling from walking into multi-GB cache directories (201s → 0.04s)
|
|
149
|
+
- **Built frontend missing from sdist**: `force-include` and `artifacts` config ensures `web/` is included; dropped frontend source from sdist
|
|
150
|
+
- **Skip known-unavailable videos during playlist backup**: Avoid re-attempting videos that are known to be unavailable
|
|
151
|
+
- **Rate-limit and concurrency implementation gaps**: Fixed three issues in the initial rate-limit implementation
|
|
152
|
+
- **e2e test fixture**: Added pytest-playwright dependency
|
|
153
|
+
|
|
154
|
+
## [0.7.0] - 2026-02-14
|
|
155
|
+
|
|
156
|
+
### Added
|
|
157
|
+
|
|
158
|
+
- **Extra metadata with DataCite vocabulary**: User-managed `extra_metadata.json` per video for supplemental metadata (related slides, papers, code repos). LinkML schema defines `RelatedResource` using DataCite v4.6 relationType and resourceTypeGeneral vocabularies. Merged additively into `metadata.json` during export (never overwrites archiver-managed fields)
|
|
159
|
+
- **Related resources display**: Frontend shows linked resources in video details with type badges (`[Presentation slides]`, `[Software]`, etc.)
|
|
160
|
+
- **Human-readable caption labels**: Caption language selector shows readable labels for yt-dlp variant suffixes (e.g. `en-cur1` → `EN (curated)`, `en-orig` → `EN (original)`)
|
|
161
|
+
- **Caption download button**: Download VTT caption files directly from the transcript panel header
|
|
162
|
+
- **Deno as core dependency**: Required for yt-dlp YouTube JS challenge solver
|
|
163
|
+
- **Skip network tests by default**: pytest addopts `-m "not network"` prevents flaky CI from YouTube bot detection. Use `tox -e network` for full network test sweep
|
|
164
|
+
|
|
165
|
+
### Fixed
|
|
166
|
+
|
|
167
|
+
- **Phased backup_channel() flow**: Refactored into discovery → fetch → store → link phases, fixing O(P^2) TSV regeneration and symlink overhead
|
|
168
|
+
- **Version injection after appVersion refactor**: Fixed placeholder matching in `deploy_frontend()` after Vite inlining changed from `v0.0.0-unknown` to bare `0.0.0-unknown`
|
|
169
|
+
- **TypeError on None playlist titles**: Handle yt-dlp returning None for playlist titles
|
|
170
|
+
- **Empty videos.tsv crash**: Handle missing `videos/` directory gracefully
|
|
171
|
+
- **Frontend build warnings**: A11y labels, version variable reference, video caption attributes
|
|
172
|
+
- **Encoding consistency**: Use `encoding="utf-8"` instead of `text=True` in all subprocess calls
|
|
173
|
+
- **yt-dlp options consistency**: Use `_get_ydl_opts()` for all yt-dlp calls, apply env vars in UserConfig
|
|
174
|
+
|
|
175
|
+
### Changed
|
|
176
|
+
|
|
177
|
+
- **Header renamed to AnnexTube**: Links to GitHub repo https://github.com/con/annextube
|
|
178
|
+
- **ejs:github enabled by default**: Remote JavaScript components for yt-dlp challenge solver
|
|
179
|
+
- **Test infrastructure**: pytest tmp_path fixture, datalad in test deps, playwright skip when missing, dedicated network test environment
|
|
180
|
+
|
|
181
|
+
## [0.6.0] - 2026-02-14
|
|
182
|
+
|
|
183
|
+
### Added
|
|
184
|
+
|
|
185
|
+
- **URL permalink for caption search state**: Shared links now also restore caption search context — query, case-sensitive/regex/filter toggles, and match position. URL params `q`, `cs`, `re`, `filter`, `match` are appended alongside existing player params (e.g. `#/channel/X/video/Y?tab=local&t=90&lang=en&q=neuroimaging&cs=1&re=1&filter=1&match=3`). Match position is restored on first load, then resets normally on new searches.
|
|
186
|
+
|
|
187
|
+
## [0.5.0] - 2026-02-13
|
|
188
|
+
|
|
189
|
+
### Added
|
|
190
|
+
|
|
191
|
+
- **URL permalink for video player state**: Shared links now restore the full viewing context — active player tab (archive/youtube), wide mode, transcript visibility, playback position, and caption language. URL params are appended to the hash route (e.g. `#/channel/X/video/Y?tab=youtube&wide=1&t=90&transcript=0&lang=es`). Only non-default values are written, keeping URLs clean. Uses `history.replaceState` to avoid history pollution.
|
|
192
|
+
|
|
193
|
+
## [0.4.0] - 2026-02-13
|
|
194
|
+
|
|
195
|
+
### Added
|
|
196
|
+
|
|
197
|
+
- **Interactive caption/transcript browser**: Side-by-side panel next to video player with full transcript display, click-to-seek, and active cue highlighting synced to playback position
|
|
198
|
+
- **Transcript search**: Search within captions with case-sensitive (C), regex (.*), and filter (F) modes. Filter mode hides non-matching cues; dim mode preserves timeline context. Enter/Shift+Enter keyboard navigation between matches with N/M position indicator
|
|
199
|
+
- **WebVTT parser with auto-caption dedup**: Zero-dependency parser handles YouTube auto-caption rolling 3-cue pattern (display→snapshot→carry-over), merging overlapping cues and stripping carry-over lines. Reduces a 1-hour video from ~4000 raw cues to ~1400 clean cues
|
|
200
|
+
- **Wide/theater mode**: Toggle (button or `t` key) to use full browser width for video+transcript layout, persisted in localStorage
|
|
201
|
+
- **Language selector**: Switch between available caption languages in the transcript panel
|
|
202
|
+
- **Auto-scroll with manual override**: Transcript auto-scrolls to active cue during playback, pauses on manual scroll, re-enables after 5s idle or cue click. "Resume auto-scroll" button when disabled
|
|
203
|
+
- **GitHub Pages sharing**: `annextube unannex` command and `prepare-ghpages` workflow for sharing archives via GitHub Pages
|
|
204
|
+
- **Frontend download button**: Download local video files directly from the player
|
|
205
|
+
- **YouTube external links**: "View on YouTube" button with source URL
|
|
206
|
+
|
|
207
|
+
### Fixed
|
|
208
|
+
|
|
209
|
+
- **Per-playlist videos.tsv**: Use `os.walk` to follow directory symlinks when indexing playlist videos
|
|
210
|
+
- **Playlist symlink indexing**: Fixed per-playlist videos.tsv generation
|
|
211
|
+
- **DataLoader archive root discovery**: Probe ascending paths at runtime instead of assuming fixed `../` relative path, enabling deployment at any URL depth
|
|
212
|
+
- **Click-to-seek scroll glitch**: Set activeCueIndex immediately on cue click to prevent afterUpdate scrolling to the old active cue while the async seek completes
|
|
213
|
+
- **Search regex statefulness**: Removed `g` flag from shared searchRegex — `RegExp.test()` with `g` advances `lastIndex`, breaking match detection in loops across different strings
|
|
214
|
+
- **Wide→normal height revert**: CSS Grid `align-items: start` breaks the circular dependency where `--player-height` was measured from the grid-row height inflated by the caption browser
|
|
215
|
+
- **Search nav button clipping**: Redesigned as two-row layout — search options on row 1, navigation (Filter + Prev/Next) on conditional row 2
|
|
216
|
+
- **Filter→unfilter scroll position**: Scroll to current match when exiting filter mode instead of jumping to top
|
|
217
|
+
- **Caption file path**: Fixed `getCaptionPath` in DataLoader to use `video.{lang}.vtt` naming (was `caption_{lang}.vtt`)
|
|
218
|
+
- **Missing captions in transcript browser**: Reconcile `captions_available` in metadata.json with actual VTT files on disk during export. Fixes videos where captions were downloaded but metadata wasn't re-saved
|
|
219
|
+
- **YouTube customUrl field**: Strip leading `@` from API response
|
|
220
|
+
|
|
221
|
+
### Changed
|
|
222
|
+
|
|
223
|
+
- **Simplified unannex**: Replaced 632-line implementation with thin git-annex wrapper
|
|
224
|
+
- **Version injection**: Use `0.0.0-unknown` placeholder in frontend build, replaced at deploy time by `deploy_frontend()`
|
|
225
|
+
- **Video+transcript layout**: CSS Grid with `align-items: start` and dynamic `--player-height` variable ensures transcript panel matches video height exactly
|
|
226
|
+
|
|
227
|
+
## [0.3.0] - 2026-02-11
|
|
228
|
+
|
|
229
|
+
### Added
|
|
230
|
+
|
|
231
|
+
- **Batch YouTube API calls**: Pre-fetch statistics and metadata in bulk instead of per-video API calls
|
|
232
|
+
- **`--comments-depth` CLI option**: Override comments depth at backup time (-1=unlimited, 0=disabled, N=limit)
|
|
233
|
+
- **DataLad dataset support**: `--datalad` flag for `init` command to create DataLad-managed archives
|
|
234
|
+
- **Version display in web UI**: Show annextube version in the header, injected during `generate-web`
|
|
235
|
+
- **Channel permalink routing**: Direct URLs to channels and per-channel playlist support in web UI
|
|
236
|
+
- **TSV regeneration for multi-channel collections**: `--update=tsv_metadata` works across collections
|
|
237
|
+
- **`serve --regenerate=web`**: Allow creating the web directory if it doesn't exist yet
|
|
238
|
+
|
|
239
|
+
### Fixed
|
|
240
|
+
|
|
241
|
+
- **Incremental backup discarding new videos**: Social date window filter was incorrectly applied to new video discovery in incremental mode, silently dropping videos published outside the 1-week window
|
|
242
|
+
- **Frontend URL state feedback loop**: Changing any filter caused a hashchange → restoreFromURL → re-render cycle, visibly resetting selections. Fixed with `history.replaceState()` instead of `window.location.hash`
|
|
243
|
+
- **URL defaults pollution**: Default sort params (`sort=date&dir=desc`) no longer appended to clean URLs
|
|
244
|
+
- **Video player paths at subpath deployments**: Absolute `/videos/...` paths replaced with relative `../videos/...` for correct resolution at any deployment subpath
|
|
245
|
+
- **Video player reactivity**: Fixed state not updating when video prop changes
|
|
246
|
+
- **Video availability checking**: Use HEAD requests instead of relying on TSV download_status; include 'tracked' status; centralized checking logic
|
|
247
|
+
- **VideoPlayer thumbnail fallback**: Use YouTube CDN thumbnail when video not downloaded locally
|
|
248
|
+
- **Video metadata/comments loading**: Use file_path from video object instead of reconstructing paths
|
|
249
|
+
- **Browser back/forward navigation**: Fixed multi-channel video metadata loading on history navigation
|
|
250
|
+
- **Page reloads and playlist selection**: Fixed routing to preserve context and support nested routes
|
|
251
|
+
- **TSV field escaping**: Properly escape newlines and special characters in TSV output
|
|
252
|
+
- **Unicode encoding errors**: Fixed encoding issues in channel avatar display
|
|
253
|
+
- **Metadata sync**: Sync metadata.json download_status with actual file system state during TSV generation
|
|
254
|
+
|
|
255
|
+
### Changed
|
|
256
|
+
|
|
257
|
+
- **Asset filenames**: Vite build now produces clean filenames (`index.js`, `index.css`) without content hashes
|
|
258
|
+
- **FilterPanel initialization**: Uses Svelte `tick()` for clean reactive cycle during mount
|
|
259
|
+
|
|
260
|
+
## [0.2.2] - 2026-02-09
|
|
261
|
+
|
|
262
|
+
### Added
|
|
263
|
+
|
|
264
|
+
- **Multi-channel collections**: Hierarchical structure with channels.tsv, aggregate/export/generate-web/serve commands
|
|
265
|
+
- **Auto-generate channel.json**: Automatically created during backup for seamless multi-channel integration
|
|
266
|
+
- **YouTube API channel metadata**: Three-tier extraction (API → yt-dlp → archive) for complete channel information
|
|
267
|
+
- **Channel avatar download**: Automatic download with MIME type detection and git-annex tracking
|
|
268
|
+
- **Timestamp filtering for channel.json**: Prevents unnecessary commits when only timestamps change
|
|
269
|
+
- **Quota exceeded auto-retry**: Automatic wait and retry when YouTube API quota is exceeded
|
|
270
|
+
- **Periodic checkpoint commits**: Configurable intermediate commits during long backup operations with interruption recovery
|
|
271
|
+
- **Configurable playlist symlink patterns**: Use {video_id}, {video_title}, {position} in playlist symlinks
|
|
272
|
+
- **Archive discovery helpers**: Central discovery system for single-channel vs multi-channel detection
|
|
273
|
+
|
|
274
|
+
### Fixed
|
|
275
|
+
|
|
276
|
+
- **Playlist video reprocessing**: Skip reprocessing existing videos in 'playlists' update mode
|
|
277
|
+
- **Caption download for existing videos**: Properly download captions when adding to existing archive
|
|
278
|
+
- **Incremental playlist optimization**: Skip unavailable videos in incremental mode for faster processing
|
|
279
|
+
- **Path pattern validation**: Fail early on unknown placeholders in video_path_pattern
|
|
280
|
+
- **E2E test environment**: Use 'uv run annextube' to ensure correct environment activation
|
|
281
|
+
- **Type checking**: Complete mypy compliance across all modules
|
|
282
|
+
- **Linting**: Full ruff compliance across all modules
|
|
283
|
+
|
|
284
|
+
### Changed
|
|
285
|
+
|
|
286
|
+
- **Default include-playlists**: Changed from 'none' to 'all' for better discoverability
|
|
287
|
+
- **Default include-podcasts**: Changed from 'none' to 'all' for consistency
|
|
288
|
+
- **Default playlist path pattern**: Changed from {playlist_id} to {playlist_title} for readability
|
|
289
|
+
- **Config template formatting**: Simplified double-brace escaping for better readability
|
|
290
|
+
|
|
291
|
+
### Documentation
|
|
292
|
+
|
|
293
|
+
- **Quota handling guide**: Complete documentation for YouTube API quota management
|
|
294
|
+
- **Checkpoint system guide**: Documentation for periodic commits and recovery
|
|
295
|
+
- **Multi-channel collections**: End-to-end guide for creating and managing collections
|
|
296
|
+
- **yt-dlp challenge solver**: Documented dependency issues and solutions
|
|
297
|
+
|
|
298
|
+
## [0.2.0] - 2026-02-05
|
|
299
|
+
|
|
300
|
+
### Added
|
|
301
|
+
|
|
302
|
+
- **Incremental social data updates**: Efficient API-optimized updates with statistics gate and early stopping (96% API request reduction)
|
|
303
|
+
- **Containerization support**: Complete Podman/Docker/Singularity recipes with documentation
|
|
304
|
+
- **Progress indicators**: Real-time feedback for long-running playlist/channel fetches
|
|
305
|
+
- **Video file validation**: Magic byte detection to identify HTML error pages disguised as videos
|
|
306
|
+
- **YouTube Data API integration**: Enhanced metadata and comment fetching with yt-dlp fallback
|
|
307
|
+
- **Per-source component configuration**: Override global settings per channel/playlist
|
|
308
|
+
- **User-wide configuration**: Cookies, proxy, network settings in ~/.config/annextube/config.toml
|
|
309
|
+
- **Hierarchical video structure**: Year/month subdirectories for better organization
|
|
310
|
+
- **Range server with annextube serve**: Local playback with seeking support
|
|
311
|
+
- **Comprehensive E2E test suite**: Playwright tests for web UI and complete workflows
|
|
312
|
+
- **Full web frontend**: Search, filter, sort, video player with local/YouTube tabs
|
|
313
|
+
|
|
314
|
+
### Fixed
|
|
315
|
+
|
|
316
|
+
- **Nested directory bug**: git-annex addurl with relative paths creating nested structures
|
|
317
|
+
- **EJS solver integration**: Support for authenticated access with cookies + deno
|
|
318
|
+
- **Playlist creation bug**: Ensure playlists are created with correct video associations
|
|
319
|
+
- **Download status detection**: Proper differentiation between tracked and downloaded videos
|
|
320
|
+
- **Video player issues**: Blank screen, iframe sizing, seeking with range requests
|
|
321
|
+
- **git-annex addurl**: Remove --no-raw flag to avoid conflicts with --fast
|
|
322
|
+
- **Cookie path handling**: Remove quotes from git-annex cookie configuration
|
|
323
|
+
- **Code quality**: Complete mypy and ruff linting fixes
|
|
324
|
+
|
|
325
|
+
### Changed
|
|
326
|
+
|
|
327
|
+
- **Test infrastructure**: Dedicated AnnexTube test channel with 10 videos and 5 playlists
|
|
328
|
+
- **E2E browser setup**: Avoid sudo prompts by checking existing installations
|
|
329
|
+
- **Default update mode**: Changed to all-incremental (videos + social data updates)
|
|
330
|
+
|
|
331
|
+
### Documentation
|
|
332
|
+
|
|
333
|
+
- Complete frontend MVP documentation with phase-by-phase progress
|
|
334
|
+
- Container deployment guide for Podman/Docker/Singularity
|
|
335
|
+
- User configuration documentation with cookie and network settings examples
|
|
336
|
+
|
|
337
|
+
## [0.1.0] - 2026-01-28
|
|
338
|
+
|
|
339
|
+
Initial release with core YouTube archival functionality:
|
|
340
|
+
- Channel and playlist backup
|
|
341
|
+
- git-annex integration for efficient storage
|
|
342
|
+
- Metadata extraction (JSON + TSV)
|
|
343
|
+
- Caption and thumbnail downloads
|
|
344
|
+
- Comment fetching
|
|
345
|
+
- Basic web UI for browsing archives
|
|
346
|
+
|
|
347
|
+
[0.12.0]: https://github.com/con/annextube/compare/v0.11.0...v0.12.0
|
|
348
|
+
[0.11.0]: https://github.com/con/annextube/compare/v0.10.0...v0.11.0
|
|
349
|
+
[0.10.0]: https://github.com/con/annextube/compare/v0.9.0...v0.10.0
|
|
350
|
+
[0.9.0]: https://github.com/con/annextube/compare/v0.8.0...v0.9.0
|
|
351
|
+
[0.8.0]: https://github.com/con/annextube/compare/v0.7.0...v0.8.0
|
|
352
|
+
[0.7.0]: https://github.com/con/annextube/compare/v0.6.0...v0.7.0
|
|
353
|
+
[0.6.0]: https://github.com/con/annextube/compare/v0.5.0...v0.6.0
|
|
354
|
+
[0.5.0]: https://github.com/con/annextube/compare/v0.4.0...v0.5.0
|
|
355
|
+
[0.4.0]: https://github.com/con/annextube/compare/v0.3.0...v0.4.0
|
|
356
|
+
[0.3.0]: https://github.com/con/annextube/compare/v0.2.2...v0.3.0
|
|
357
|
+
[0.2.2]: https://github.com/con/annextube/compare/v0.2.0...v0.2.2
|
|
358
|
+
[0.2.0]: https://github.com/con/annextube/compare/v0.1.0...v0.2.0
|
|
359
|
+
[0.1.0]: https://github.com/con/annextube/releases/tag/v0.1.0
|