# Subtitle encoding teaching files

These are original, self-authored two-cue French teaching subtitles. They are
not a movie excerpt, customer file, translation output, or playback test.
The files are intentionally different byte representations of the same known
text, including deliberately damaged copies. Do not use the damaged files as
clean subtitle sources.

- `subtitle_encoding.py`: local inspection, byte-copy backup, explicit UTF-8
  conversion. Python 3 standard library only, no network or dependencies.
- `reproduce.py`: makes the five fixtures and `results.json` inside a new
  directory. It refuses an existing directory.
- `samples/results.json`: dated environment, provenance, transformation methods,
  full decoded text, SHA-256 hashes, checks, and limitations.
- `samples/source-utf8.srt`: correct original UTF-8.
- `samples/source-windows1252.srt`: correct original text in Windows-1252.
- `samples/wrong-decoder-resaved-utf8.srt`: valid UTF-8 containing mojibake.
- `samples/replacement-resaved-utf8.srt`: valid UTF-8 containing six U+FFFD
  replacement characters. This copy has lost original character information.
- `samples/correctly-converted-utf8.srt`: explicit cp1252 conversion, byte-equal
  to the UTF-8 source.

## Reproduce

Run from the folder containing the downloaded scripts. `experiment` must not
already exist. The original measured environment was Python 3.14.3 on macOS,
2026-09-13. The scripts use only Python's standard library. Other OS/interpreter
combinations were not tested in this run. On Windows, use your Python 3 launcher
(`py -3` in place of `python3`) if that is how Python is configured.

```sh
python3 reproduce.py experiment
python3 subtitle_encoding.py inspect experiment/source-windows1252.srt --encoding cp1252 --line 3
python3 subtitle_encoding.py backup experiment/source-windows1252.srt original-bytes.srt
python3 subtitle_encoding.py convert original-bytes.srt repaired-utf8.srt --from-encoding cp1252
python3 subtitle_encoding.py inspect repaired-utf8.srt --line 7
```

Expected repaired SHA-256:
`67d72f6b09337c686175f676aaf6a8f633765ed3244261e62e818d21fceb6748`.
This hash identifies this teaching text only, not what your subtitle should be.

Inspection prints ASCII-safe JSON: `\u00e9` represents `é`. `--line` reports
Unicode names and code points without relying on a terminal font. A successful
decode only means the bytes are legal for the codec you selected. It does not
prove the language is right, that the file is valid SRT, or that timing matches
a video. Inspection never repairs text.

Conversion requires `--from-encoding`; it never guesses. Existing destinations
are refused, including the source path. Strict decode errors and decoded
U+FFFD stop conversion before output is created. U+FFFD can be intentional; the
tool deliberately refuses that case too. Do not remove markers merely to
force success. Complete decoded text is retained, including cue lines and
line endings; only the byte encoding changes. Output bytes are read back.

For a confirmed UTF-8 source with a BOM, select `utf-8-sig`. Plain `utf-8`
leaves U+FEFF in decoded text, which conversion refuses at the start of a file.
The normal output has no BOM; `--with-bom` explicitly adds one. Choose from the
actual receiving application's requirements, not a claim of universal player
compatibility. Non-UTF8 source signatures need separate investigation.

An I/O failure can leave a partial _new_ destination; the command reports
failure. Do not use it, and use a fresh destination name on the next attempt.
The tool has no overwrite or cleanup mode. It does not normalize, fix timing,
repair SRT syntax, infer missing letters, or automatically reverse mojibake.

The deliberate `errors="replace"` and inverse-mojibake operations in
`reproduce.py` are controlled demonstrations of known history, not commands to
apply blindly to a real subtitle.

## License

The scripts and original teaching fixtures are available under the included
MIT license. All dates in the result file describe local evidence generation,
not a product release or publication date.
