# Changelog of YouTube Transcript & Subtitles Scraper API (`zovo-one/tubetext-youtube-transcript-scraper`) Actor

- **URL**: https://apify.com/zovo-one/tubetext-youtube-transcript-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/zovo-one/tubetext-youtube-transcript-scraper.md

## Changelog

### 0.1.2 (2026-11-05)

Fix round 2 after the second independent review. Not yet published.

- The input form no longer says that listed videos are charged as playlist items. Listing is free, and a video is charged only when its transcript is saved.
- In SRT, any run of two or more hyphens before `>` (`-->`, `--->`, `---->`) in cue text becomes `->`, so cue text can never look like a timing line.
- The traffic guard now stops the run above 225 KB of response body per video on average (was 400 KB), checked from 3 videos (was 10). Listing traffic is no longer counted in that average (new stat `listingBodyBytes`). The warning above 150 KB applies from the first video.
- The player API key is kept between runs in the named key-value store `tubetext-state`, so a run whose key-less player call is refused tries the saved key before it reads a 340 KB watch page. A refused saved key is dropped. New stat `savedApiKeyLoaded`. The run log warns when a watch page was needed.

### 0.1.1 (2026-11-05)

Fix round 1 after the independent review. Not yet published.

- The price is now one `video` event at $0.0025 per saved transcript. The `playlist-item` event is gone, so a video from a playlist or channel costs the same as a direct one, and its error row is free.
- A malformed `%` escape in an `@handle` URL gives an `INVALID_INPUT` row instead of failing the run. A caption track that needs a proof-of-origin token is no longer retried.
- The watch-page fallback reads the API key once per run and reuses it (at most 5 watch pages per run). It adds the run stats `responseBodyBytes`, `responseBodyKBPerVideo`, `watchPageFetches` and `videosNotStarted`. A traffic guard stops the run above 400 KB per video on average.
- A video that YouTube reports as live gives `LIVE_NOT_FINISHED`. The README now says that an ended stream without a recording gives `VIDEO_UNPLAYABLE`. Language matching respects scripts, so `zh-TW` no longer takes a `zh-Hans` track and `sr-Latn` no longer takes `sr-Cyrl`. WebVTT cue text escapes `&`, `<` and `>`, and SRT writes `-->` in text as `->`. Only formatting tags are stripped, so literal text like `a < b > c` is kept.
- When the budget looks full, a worker waits for running videos (a failed video frees its share) instead of stopping at once.

### 0.1.0 (2026-11-05)

First version, built and tested locally and not yet published.

- Transcripts for videos, playlists (first N videos) and channels (latest N uploads) in one run.
- A language preference list. Captions written by a person come before auto-generated ones, region variants are matched, and an optional fallback returns the original language.
- Output as timestamped segments, plain text, SRT or WebVTT, with title, channel, publish date, duration, views and category. Plain text is always included.
- Per-video error rows with stable error codes. Error rows aren't charged. Retries use exponential backoff and Retry-After, and a blocked video is retried through a new proxy session.
- Pay per event (prices replaced in 0.1.1). A video only starts when its charges fit the run's budget.

The engine (`src/engine/`) has no Apify imports, so it can later back an npm CLI and an MCP server.
