faceless-qc-lite 2.0.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.
- faceless_qc_lite-2.0.0/LICENSE +21 -0
- faceless_qc_lite-2.0.0/PKG-INFO +383 -0
- faceless_qc_lite-2.0.0/README.md +357 -0
- faceless_qc_lite-2.0.0/pyproject.toml +57 -0
- faceless_qc_lite-2.0.0/setup.cfg +4 -0
- faceless_qc_lite-2.0.0/src/caption_toolkit.py +970 -0
- faceless_qc_lite-2.0.0/src/faceless_qc_lite.egg-info/PKG-INFO +383 -0
- faceless_qc_lite-2.0.0/src/faceless_qc_lite.egg-info/SOURCES.txt +22 -0
- faceless_qc_lite-2.0.0/src/faceless_qc_lite.egg-info/dependency_links.txt +1 -0
- faceless_qc_lite-2.0.0/src/faceless_qc_lite.egg-info/entry_points.txt +2 -0
- faceless_qc_lite-2.0.0/src/faceless_qc_lite.egg-info/top_level.txt +7 -0
- faceless_qc_lite-2.0.0/src/faceless_qc_lite.py +159 -0
- faceless_qc_lite-2.0.0/src/faceless_qc_suite.py +458 -0
- faceless_qc_lite-2.0.0/src/link_rot.py +964 -0
- faceless_qc_lite-2.0.0/src/retention_checker.py +577 -0
- faceless_qc_lite-2.0.0/src/shorts_packager.py +429 -0
- faceless_qc_lite-2.0.0/src/thumbnail_checker.py +447 -0
- faceless_qc_lite-2.0.0/tests/test_caption_toolkit.py +745 -0
- faceless_qc_lite-2.0.0/tests/test_faceless_qc_lite.py +72 -0
- faceless_qc_lite-2.0.0/tests/test_faceless_qc_suite.py +195 -0
- faceless_qc_lite-2.0.0/tests/test_link_rot.py +537 -0
- faceless_qc_lite-2.0.0/tests/test_retention_checker.py +495 -0
- faceless_qc_lite-2.0.0/tests/test_shorts_packager.py +257 -0
- faceless_qc_lite-2.0.0/tests/test_thumbnail_checker.py +393 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jasveer Singh
|
|
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.
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: faceless-qc-lite
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Pre-upload QC for faceless video: the 5 anchor checks plus caption, thumbnail, retention, Shorts-title and link-rot checks — one suite, one receipt.
|
|
5
|
+
Author: Jasveer Singh
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/jasveerai88/faceless-qc-lite
|
|
8
|
+
Project-URL: Repository, https://github.com/jasveerai88/faceless-qc-lite
|
|
9
|
+
Project-URL: Issues, https://github.com/jasveerai88/faceless-qc-lite/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/jasveerai88/faceless-qc-lite/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: video,youtube,shorts,captions,quality-control,ffmpeg,cli
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Multimedia :: Video
|
|
21
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
<h1 align="center">faceless-qc-lite</h1>
|
|
28
|
+
|
|
29
|
+
<p align="center"><strong>Every pre-upload check a faceless creator runs — one command, one receipt.</strong></p>
|
|
30
|
+
|
|
31
|
+
<p align="center">
|
|
32
|
+
<img alt="tests: 241 passing" src="https://img.shields.io/badge/tests-241%20passing-brightgreen">
|
|
33
|
+
<img alt="python 3.10 | 3.11 | 3.12" src="https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue">
|
|
34
|
+
<img alt="version 2.0.0" src="https://img.shields.io/badge/version-2.0.0-orange">
|
|
35
|
+
<img alt="dependencies: none" src="https://img.shields.io/badge/dependencies-0-brightgreen">
|
|
36
|
+
<img alt="license: MIT" src="https://img.shields.io/badge/license-MIT-blue">
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
<p align="center"><img alt="faceless-qc-lite demo: the combined suite receipt on a planted-problem fixture — a too-quiet 640x360 video, racing captions, a 320x180 thumbnail, an over-long Shorts title and a dead shortener link — verdict HOLD" src="demo.gif" width="880"></p>
|
|
40
|
+
|
|
41
|
+
A faceless video can fail in six places, and until now
|
|
42
|
+
each one had its own tool. The video itself can be too
|
|
43
|
+
quiet, gapped, or the wrong size. The captions can race
|
|
44
|
+
or arrive structurally broken from raw transcription.
|
|
45
|
+
The thumbnail can be 320×180. The Short can bleed its
|
|
46
|
+
first seconds. The title can truncate mid-word. The
|
|
47
|
+
description links can point at services that shut down
|
|
48
|
+
last year.
|
|
49
|
+
|
|
50
|
+
faceless-qc-lite v1 (2026-10-31) checked the first
|
|
51
|
+
place — the video file: loudness, dead air, black
|
|
52
|
+
frames, caption speed, resolution. **v2.0.0 is the
|
|
53
|
+
merge:** five published tools — caption-toolkit,
|
|
54
|
+
thumbnail-checker, retention-checker, shorts-packager,
|
|
55
|
+
link-rot — became check modules of this suite. One
|
|
56
|
+
install, one pre-upload run, one QC receipt.
|
|
57
|
+
|
|
58
|
+
Local only: nothing is ever uploaded anywhere, and the
|
|
59
|
+
link audit never even fetches a link.
|
|
60
|
+
|
|
61
|
+
It earns its keep on real files. The run that started
|
|
62
|
+
this project, back at v1.0.0:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
Faceless QC Lite — intro-loop.mp4
|
|
66
|
+
[HOLD] Loudness: integrated loudness -21.6 LUFS (target -14 +/-2)
|
|
67
|
+
[PASS] Dead air: longest in-story silence 0.0s
|
|
68
|
+
[PASS] Black frames: no black segments >= 0.5s
|
|
69
|
+
Verdict: HOLD
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
That file was heading for upload 7.6 LUFS too quiet.
|
|
73
|
+
Lite caught it in seconds.
|
|
74
|
+
|
|
75
|
+
## Quick start
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pipx install faceless-qc-lite # or: pip install faceless-qc-lite
|
|
79
|
+
faceless-qc-lite my-video.mp4
|
|
80
|
+
faceless-qc-lite suite my-video.mp4 --captions my-video.srt \
|
|
81
|
+
--thumbnail thumb.png --title "My Title" \
|
|
82
|
+
--hashtags "#shorts" --catalogue catalogue.json
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
*(The PyPI name goes live when v2.0.0 is published;
|
|
86
|
+
until then use a source checkout:
|
|
87
|
+
`python3 src/faceless_qc_lite.py <video>` for the
|
|
88
|
+
anchor, or
|
|
89
|
+
`pipx install git+https://github.com/jasveerai88/faceless-qc-lite`.)*
|
|
90
|
+
|
|
91
|
+
Needs Python 3.10+ and **FFmpeg on PATH** (the anchor
|
|
92
|
+
and retention checks measure with ffmpeg/ffprobe).
|
|
93
|
+
No accounts, no API keys, no dependencies.
|
|
94
|
+
|
|
95
|
+
The anchor's own command line is unchanged from v1.x —
|
|
96
|
+
exit 0 PASS, 2 HOLD, 1 error — so existing pipelines
|
|
97
|
+
keep working:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
faceless-qc-lite my-video.mp4
|
|
101
|
+
faceless-qc-lite my-video.mp4 --captions my-video.srt
|
|
102
|
+
# from a checkout, the anchor still runs exactly as it always has:
|
|
103
|
+
python3 src/faceless_qc_lite.py my-video.mp4
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## What it checks
|
|
107
|
+
|
|
108
|
+
| Check | Command | What it catches | Verdict words |
|
|
109
|
+
|---|---|---|---|
|
|
110
|
+
| **The anchor — the video file** | `faceless-qc-lite VIDEO` (or `check VIDEO`) | Loudness vs the −14 LUFS streaming target (±2), longest in-story dead air (warn >2.5s, HOLD >4s), black frames ≥0.5s, caption speed from a `.srt`/`.vtt` sidecar, resolution + orientation | PASS / WARN / HOLD / SKIP |
|
|
111
|
+
| **Captions** | `captions check\|fix\|lint\|repair\|convert` | Caption speed gates, plus the structural lint/repair raw transcription output needs (timing, overlaps, malformed cues) | PASS / WARN / HOLD |
|
|
112
|
+
| **Thumbnail** | `thumbnail IMAGE` | Real dimensions parsed from the file header, data integrity, aspect ratio, file size, filename SEO | PASS / WARN / FAIL |
|
|
113
|
+
| **Retention** | `retention VIDEO` | Hook window, dead zones, pacing, loudness, platform spec (Shorts / long-form / TikTok) on the finished video | PASS / WARN / HOLD |
|
|
114
|
+
| **Shorts title** | `package --title T [--hashtags H]` | Fits a Shorts title + hashtags into the 100-visible-character cap, wording untouched — it truncates at a word boundary and says so, or moves hashtags to the description | PASS / PASS_WITH_OVERFLOW / TRUNCATED |
|
|
115
|
+
| **Description links** | `links audit\|links CATALOGUE` | Structural rot in a description-link catalogue: placeholder hosts, dead domains, malformed URLs — audited offline, never fetched | findings by class; exit 0 clean / 1 findings |
|
|
116
|
+
|
|
117
|
+
The combined `suite` run executes the anchor plus every
|
|
118
|
+
module that applies to the inputs given. A module with
|
|
119
|
+
nothing to run on reports **SKIPPED with its reason** —
|
|
120
|
+
a skip is never counted as a pass. Suite verdict: HOLD
|
|
121
|
+
if any module HOLDs or FAILs (exit 2), PASS WITH
|
|
122
|
+
WARNINGS if any module warns (exit 0), else PASS.
|
|
123
|
+
Every module also runs standalone behind the suite
|
|
124
|
+
command, and every one accepts `--json` (one object;
|
|
125
|
+
the suite's object nests each module's own).
|
|
126
|
+
|
|
127
|
+
## The receipt — a real run
|
|
128
|
+
|
|
129
|
+
`examples/make_fixture.py` builds a fixture set with
|
|
130
|
+
one planted problem per module: a very quiet 640×360
|
|
131
|
+
video with a 3.5s black, silent gap; a captions file
|
|
132
|
+
whose second cue races at 138 CPS; a 320×180 thumbnail
|
|
133
|
+
with spaces in its filename; an over-100-character
|
|
134
|
+
Shorts title; a catalogue holding a goo.gl link and an
|
|
135
|
+
example.com placeholder. The run below is captured
|
|
136
|
+
output, reproduced verbatim — build the fixture and
|
|
137
|
+
diff it yourself.
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
faceless-qc-lite suite video.mp4 --captions captions.srt \
|
|
141
|
+
--thumbnail "My Video Thumb.png" \
|
|
142
|
+
--title "I Tried the Hardest Faceless Video Challenge for Thirty Days and the Results Were Honestly Unbelievable" \
|
|
143
|
+
--hashtags "#shorts #faceless" --catalogue catalogue.json
|
|
144
|
+
# exit code: 2
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
Faceless QC Lite — suite receipt for video.mp4
|
|
149
|
+
|
|
150
|
+
Faceless QC Lite — video.mp4
|
|
151
|
+
[HOLD] Loudness: integrated loudness -38.5 LUFS (target -14 +/-2)
|
|
152
|
+
[WARN] Dead air: silence 3.5s at 2.0s (warn > 2.5s)
|
|
153
|
+
[WARN] Black frames: 1 black segment(s), first 2.0s-5.5s
|
|
154
|
+
[HOLD] Caption speed: caption speed median 76.0 CPS, max 138.0 (HOLD: median >20 or max >30)
|
|
155
|
+
[HOLD] Resolution: 640x360 landscape — short side 360px is below 720p (HOLD)
|
|
156
|
+
Verdict: HOLD
|
|
157
|
+
|
|
158
|
+
== retention-checker ==
|
|
159
|
+
retention-checker v0.2.0 — video.mp4
|
|
160
|
+
Platform: youtube-shorts · Duration: 8.0s · 640x360
|
|
161
|
+
[WARN] Hook window: first caption content at 0.0s (short video — second-beat window is the whole runtime); title words do not appear in the first 8.5s of captions — the hook does not echo the title's promise
|
|
162
|
+
[WARN] Dead zones: 1 dead zone(s) > 2.5s in the first 80%: 2.0s-5.5s (3.5s)
|
|
163
|
+
[HOLD] Pacing: caption speed median 76.0 CPS, max 138.0 (2 captions from captions.srt) (HOLD: median > 20 or max > 30)
|
|
164
|
+
[HOLD] Loudness: integrated loudness -38.5 LUFS — outside the -16 to -12 LUFS window (target -14 +/-2)
|
|
165
|
+
[HOLD] Platform spec: 640x360 landscape — youtube-shorts is a vertical format; a non-vertical video is pillarboxed or cropped
|
|
166
|
+
Verdict: HOLD
|
|
167
|
+
|
|
168
|
+
== caption-toolkit — check ==
|
|
169
|
+
caption-toolkit check — captions.srt
|
|
170
|
+
#1 00:00:00.000 --> 00:00:02.000 | 28 chars / 2.00s = 14.0 CPS
|
|
171
|
+
#2 00:00:06.000 --> 00:00:06.500 | 69 chars / 0.50s = 138.0 CPS <-- HOLD (>30 CPS)
|
|
172
|
+
Captions: 2 | median 76.0 CPS | max 138.0 CPS
|
|
173
|
+
Verdict: HOLD (PASS median <=17, WARN median >17, HOLD median >20 or any >30)
|
|
174
|
+
|
|
175
|
+
== thumbnail-checker ==
|
|
176
|
+
File: My Video Thumb.png
|
|
177
|
+
Dimensions: 320x180 (PNG), 626 bytes
|
|
178
|
+
[PASS] Format: PNG image, 320x180
|
|
179
|
+
[WARN] Resolution: 320x180 is below the recommended 1280x720 minimum for YouTube
|
|
180
|
+
[PASS] Aspect ratio: 1.78 is 16:9 (landscape / YouTube)
|
|
181
|
+
[PASS] File size: 0.6 KB
|
|
182
|
+
[WARN] Filename SEO: Filename contains spaces — use hyphens instead (e.g. my-thumbnail.jpg)
|
|
183
|
+
[PASS] Filename SEO: Filename is descriptive length
|
|
184
|
+
[PASS] Brightness/contrast (PIL): avg brightness 76/255, contrast (std) 0
|
|
185
|
+
Verdict: WARN
|
|
186
|
+
|
|
187
|
+
== shorts-packager ==
|
|
188
|
+
Title (98/100): I Tried the Hardest Faceless Video Challenge for Thirty Days and the Results Were Honestly #shorts
|
|
189
|
+
Verdict: TRUNCATED
|
|
190
|
+
Hashtags in title: 1 (#shorts)
|
|
191
|
+
Hashtags overflow to description: 1 (#faceless)
|
|
192
|
+
WARNING: Title alone is 103 chars (> 100) even without hashtags: truncated at a word boundary to 90 chars. Edit the title wording yourself for a better fit.
|
|
193
|
+
|
|
194
|
+
Description:
|
|
195
|
+
---
|
|
196
|
+
I Tried the Hardest Faceless Video Challenge for Thirty Days and the Results Were Honestly
|
|
197
|
+
|
|
198
|
+
#faceless
|
|
199
|
+
|
|
200
|
+
Credits: [add your sources / credits here]
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
== link-rot — audit ==
|
|
204
|
+
link-rot v0.1.0 — audit · catalogue catalogue.json
|
|
205
|
+
1 video(s) · 3 link occurrence(s) · 3 unique link(s)
|
|
206
|
+
Structural audit only: this tool reads text and never fetches a link.
|
|
207
|
+
A finding means the link cannot work as written, or is worth a live
|
|
208
|
+
check — never that it was loaded and failed.
|
|
209
|
+
|
|
210
|
+
Findings by class (findings, not links):
|
|
211
|
+
placeholder: 1
|
|
212
|
+
dead-domain: 1
|
|
213
|
+
|
|
214
|
+
Cannot work as written: 2 unique link(s)
|
|
215
|
+
Worth a live check: 0 unique link(s)
|
|
216
|
+
Clean: 1 unique link(s)
|
|
217
|
+
|
|
218
|
+
Per video:
|
|
219
|
+
[fixture-1] Fixture video
|
|
220
|
+
! dead-domain — https://goo.gl/abc123 — host goo.gl belongs to a service that has shut down (Google URL Shortener — Google shut it down and its links stopped resolving in August 2025) — an expired-domain risk pattern; replace it with a live target
|
|
221
|
+
! placeholder — https://example.com/plan — host example.com is a documentation placeholder — the real link was never filled in
|
|
222
|
+
|
|
223
|
+
Suite verdict: HOLD — needs attention: faceless-qc-lite, retention-checker, caption-toolkit, thumbnail-checker, shorts-packager, link-rot
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The same command on a clean control (a 720×1280 Short
|
|
227
|
+
at −14.0 LUFS with a readable sidecar, and no
|
|
228
|
+
`--thumbnail` / `--title` / `--catalogue` given) ends:
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
Suite verdict: PASS WITH WARNINGS — needs attention: faceless-qc-lite (skipped, not passed: thumbnail-checker, shorts-packager, link-rot)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
— three modules honestly SKIPPED, not passed, and the
|
|
235
|
+
exit code is 0.
|
|
236
|
+
|
|
237
|
+
## The merge — what changed, what didn't
|
|
238
|
+
|
|
239
|
+
This release executes a fleet audit
|
|
240
|
+
(FLEET-AUDIT-2026-11-04): 43 published tools were
|
|
241
|
+
audited, and 18 of the quiet ones were ordered merged
|
|
242
|
+
into 4 flagships so the fleet would be a few strong
|
|
243
|
+
tools instead of dozens of shelf orphans. This is
|
|
244
|
+
merge #2; the five absorbed tools became this suite's
|
|
245
|
+
check library.
|
|
246
|
+
|
|
247
|
+
The merge changed no engine: each module's code is
|
|
248
|
+
**byte-identical** to its source tool's, its CLI shape
|
|
249
|
+
and verdict vocabulary are unchanged, and it still
|
|
250
|
+
reports its own source version inside its own output
|
|
251
|
+
(caption-toolkit v0.3.0, thumbnail-checker v0.2.0,
|
|
252
|
+
retention-checker v0.2.0, shorts-packager v0.2.0,
|
|
253
|
+
link-rot v0.1.0) — 2.0.0 is the suite's version. The
|
|
254
|
+
anchor's engine is byte-identical to the file that has
|
|
255
|
+
shipped in this repo since v1.2.0. The suite's new
|
|
256
|
+
code is the dispatcher, the combined `suite` run, and
|
|
257
|
+
21 tests on top of the 220 the six source suites
|
|
258
|
+
carried over — 241 in total. One harness conversion,
|
|
259
|
+
named plainly: the anchor's tests were pytest-style
|
|
260
|
+
functions; the same seven checks with the same
|
|
261
|
+
assertions are now unittest methods so one discover
|
|
262
|
+
run covers everything.
|
|
263
|
+
|
|
264
|
+
Known note: the engines are installed as top-level
|
|
265
|
+
Python modules (`faceless_qc_lite`, `caption_toolkit`,
|
|
266
|
+
`thumbnail_checker`, `retention_checker`,
|
|
267
|
+
`shorts_packager`, `link_rot`) alongside the
|
|
268
|
+
`faceless_qc_suite` dispatcher. If you also installed
|
|
269
|
+
one of the original standalone tools, both installs
|
|
270
|
+
provide the same module file with identical content —
|
|
271
|
+
either copy behaves the same. And because the names
|
|
272
|
+
are plain, a same-named `.py` file in the folder you
|
|
273
|
+
run from can shadow the installed module; run from a
|
|
274
|
+
clean directory if a module ever behaves like someone
|
|
275
|
+
else's code.
|
|
276
|
+
|
|
277
|
+
### For agents
|
|
278
|
+
|
|
279
|
+
[SKILL.md](SKILL.md) states the full command surface,
|
|
280
|
+
each module's verdict vocabulary, the `suite` JSON
|
|
281
|
+
contract and the honesty limits — and makes
|
|
282
|
+
faceless-qc-lite itself installable as a skill: point
|
|
283
|
+
your agent at this repo's SKILL.md and it can run the
|
|
284
|
+
pre-upload gate before anything goes public.
|
|
285
|
+
|
|
286
|
+
## Honest limits
|
|
287
|
+
|
|
288
|
+
- **FFmpeg is a hard requirement for measurement.**
|
|
289
|
+
Without ffmpeg/ffprobe on PATH, the anchor's and
|
|
290
|
+
retention's media checks cannot measure — they
|
|
291
|
+
report SKIP / error by design. The suite never
|
|
292
|
+
guesses a measurement it couldn't take.
|
|
293
|
+
- **Caption speed is a gate, not full caption QA.**
|
|
294
|
+
The anchor judges the median (and the worst cue);
|
|
295
|
+
the per-line percentage gates are part of the full
|
|
296
|
+
Faceless QC (below).
|
|
297
|
+
- **The link audit is structural and offline.** Its
|
|
298
|
+
words are "cannot work as written" and "worth
|
|
299
|
+
checking live" — never "dead" and never "works". It
|
|
300
|
+
has not loaded your link and will not.
|
|
301
|
+
- **The thumbnail check reads headers, not taste.**
|
|
302
|
+
Dimensions, integrity, aspect, size and filename are
|
|
303
|
+
measured from the file itself (Pillow, when
|
|
304
|
+
installed, additionally verifies the image data and
|
|
305
|
+
measures brightness/contrast; without it those two
|
|
306
|
+
sub-checks skip). Whether the thumbnail is *good* is
|
|
307
|
+
still your eye's job.
|
|
308
|
+
- **The packager fits, it does not write.** An
|
|
309
|
+
over-long title is truncated at a word boundary and
|
|
310
|
+
the receipt says so, with the overflow moved to the
|
|
311
|
+
description template. Better wording stays yours.
|
|
312
|
+
- **A PASS is a floor, not a forecast.** It means
|
|
313
|
+
"none of the checked problems were found" — never
|
|
314
|
+
"this video will perform".
|
|
315
|
+
|
|
316
|
+
## The receipt family
|
|
317
|
+
|
|
318
|
+
One grammar across the fleet — *claims on one side,
|
|
319
|
+
evidence on the other, every verdict cited*:
|
|
320
|
+
|
|
321
|
+
- **[preflight-agent](https://github.com/jasveerai88/preflight-agent)
|
|
322
|
+
— is this agent setup safe to run?** Five static
|
|
323
|
+
auditors over Claude/agent configuration, one scan
|
|
324
|
+
receipt. (Merge #1 of the same audit.)
|
|
325
|
+
- **[skill-vet](https://github.com/jasveerai88/skill-vet)
|
|
326
|
+
— is this skill pack dangerous?** Stealing, spying,
|
|
327
|
+
hidden sending, each proven as a combination of
|
|
328
|
+
evidence.
|
|
329
|
+
- **[permission-audit](https://github.com/jasveerai88/permission-audit)
|
|
330
|
+
— do your allowlists grant more than you think?**
|
|
331
|
+
Claude Code permission rules, resolved the way the
|
|
332
|
+
tool itself resolves them.
|
|
333
|
+
- **[skill-claims](https://github.com/jasveerai88/skill-claims)
|
|
334
|
+
— is the package honest?** A skill's prose promises
|
|
335
|
+
audited against its static behaviour.
|
|
336
|
+
- **[spec-receipt](https://github.com/jasveerai88/spec-receipt)
|
|
337
|
+
— does the code still match the spec?** Declared
|
|
338
|
+
surfaces vs implemented surfaces, per-item verdicts.
|
|
339
|
+
- **[done-claim-auditor](https://github.com/jasveerai88/done-claim-auditor)
|
|
340
|
+
— did the agent do what it claimed?** The same
|
|
341
|
+
claim-vs-evidence logic pointed at session
|
|
342
|
+
transcripts.
|
|
343
|
+
|
|
344
|
+
faceless-qc-lite is the family's creator-side member:
|
|
345
|
+
the upload is the claim, the measurements are the
|
|
346
|
+
evidence.
|
|
347
|
+
|
|
348
|
+
## Lite vs full Faceless QC
|
|
349
|
+
|
|
350
|
+
Lite (this repo, free forever, MIT) is the suite
|
|
351
|
+
above. The full Faceless QC adds: too-few-pauses
|
|
352
|
+
intelligence, full caption gates (% of lines over
|
|
353
|
+
speed, not just the median), dynamics (LRA), an HTML
|
|
354
|
+
report naming the worst 3 moments with timestamps,
|
|
355
|
+
and one-click launchers.
|
|
356
|
+
|
|
357
|
+
## Sponsor this work
|
|
358
|
+
|
|
359
|
+
If Lite saves you one bad upload, consider sponsoring
|
|
360
|
+
— sponsorships fund new checks and keep Lite free:
|
|
361
|
+
use the **Sponsor** button above (GitHub Sponsors:
|
|
362
|
+
@jasveerai88). What each tier gets, and how to claim
|
|
363
|
+
it: [SPONSOR-REWARDS.md](SPONSOR-REWARDS.md).
|
|
364
|
+
|
|
365
|
+
## Tests
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
python3 -m unittest discover -s tests
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
241 tests: the anchor's 7 (pytest-style in v1.x, now
|
|
372
|
+
unittest wrappers with identical assertions), the
|
|
373
|
+
five module suites carried over (50 + 28 + 53 + 22 +
|
|
374
|
+
60 = 213), and 21 dispatcher/suite tests covering
|
|
375
|
+
subcommand routing, skip-with-reason reporting, the
|
|
376
|
+
combined JSON shape and exit-code ranking. Fixtures
|
|
377
|
+
are fictional; the example media under `examples/`
|
|
378
|
+
is generated locally by the scripts beside it.
|
|
379
|
+
|
|
380
|
+
## Privacy
|
|
381
|
+
|
|
382
|
+
Runs 100% locally. No telemetry, no accounts, no
|
|
383
|
+
tracking, nothing uploaded.
|