Skip to content

Add localized listing videos example - #27

Merged
dazzatronus merged 11 commits into
masterfrom
add-localized-listing-videos
Oct 15, 2026
Merged

dazzatronus merged 11 commits into
masterfrom
add-localized-listing-videos

Conversation

@musab123-afk

Copy link
Copy Markdown
Collaborator

Renders one property listing video in English, Spanish, German and Japanese from one saved template. Each language gets its own AI voice-over, captions, headline and call to action. An optional translate.py drafts missing translations with Gemini.

Companion code for https://shotstack.io/learn/video-localization-api/

Checks done:

  • Fresh clone: no key, wrong key and no network each print one line and exit 1 (all four scripts)
  • ruff (repo config) and prettier pass
  • README commands run in order on production (render.py ja, then a rerun that skips)

Choices a reviewer may question:

  • Each script has its own copy of error_detail, so each script can be copied alone.
  • render.py stops on the first connection error at startup. The next run picks up the renders.
  • If a changed language fails, the old output/.mp4 stays. The "Not rendered" line names it.
  • A submit timeout does not stop the run. The language is reported, because the render may have started.

After merge: sync the article's code blocks to this revision and add the cookbook link to the article.

Renders one property listing video in English, Spanish, German and Japanese
from one saved template, with generated voice-overs, captions and merge-field
text. Includes an optional translate.py that drafts missing translations with
Gemini. Companion code for the video localization API guide.
render.py retried a lost connection for up to 15 minutes when it picked up
a render from an earlier run. Now it stops with the network message after
six failed attempts and keeps the log entry, so the next run picks the
render up. Use python3 in docstrings, as the README does.
- Read Edit API errors ({message, response}) as well as gateway errors
  ({errors}), so a failed render or template save prints one line.
- Stop before any paid render if a language has an empty field.
- Stop on a submit timeout, because the render may have started.
- Render again when a finished video was deleted, instead of downloading
  an expired URL.
- Name the language and Gemini's reason when a translation is blocked or
  cut off.
- Stop polling on the overwritten Ingest status, and do not tell the user
  to upload again after a timeout.
upload_footage.py now reads the error the same way as render.py and
save_template.py. The empty-field message says what translate.py fills.
The submit-timeout message no longer names a dashboard page.
- error_detail falls back to the raw body for any error shape it cannot read.
- A finished video that was deleted downloads again from the old render,
  as before. A render again happens only when the URL has expired.
- A submit timeout no longer stops the run. The other languages still
  render and download.
- translate.py handles a non-JSON reply, and no longer says to run again
  after a blocked prompt.
- The empty-field check also rejects fields with only spaces.
- upload_footage.py names the source ID when a status check fails, and
  says how to get its status after a timeout.
@vercel

vercel Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
reelestate Ignored Ignored Preview Oct 15, 2026 4:33am UTC

- Stop with one line when languages.json or renders.json is not valid JSON,
  or when an entry has no code.
- Stop with one line when a finished render has no video URL.
- Require requests 2.18, which made Response a context manager.
- Write one instruction in each README sentence.
- A submit with no answer is reported apart from failed renders. The final
  line says a new run renders it again and uses credits again.
- A null field counts as empty. translate.py uses the same empty test as
  render.py, so a field with only spaces gets translated.
- A done render with no URL is rendered again on the next run.
- error_detail falls back to the raw body when the message is empty.
- languages.json must be a list with at least one language.
- A Gemini reply with no usable translation says what to do next.
- languages.json may not use one code twice.
- An unexpected reply for one language no longer stops the other languages.
- An empty translation from Gemini is an error, not a saved translation.
- error_detail falls back to the error title, then the HTTP reason.
- The README says what happens after a request gets no answer.

Copy link
Copy Markdown
Contributor

Please preserve the saved render ID when a download gets HTTP 429. Currently it’s deleted, so rerunning submits another paid render instead of retrying the download. Add a regression test covering that retry.

A download that got HTTP 429 deleted the saved render ID, so the next run
paid for a new render instead of downloading the finished one. A rate
limit, a request timeout or a server error now keeps the render, and
only another 4xx (an expired URL) starts a new render. The same rule is
used when the render status is checked.

test_render.py covers the retry: after a failed download the next run
downloads the same render and does not submit again. CI runs the tests
of each Python example that has a test file.

@dazzatronus dazzatronus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 429 retry issue is fixed: temporary download failures retain the render ID, and rerunning resumes the existing render without another submission. All five regression tests pass locally; the 429 test also fails against the previous revision, confirming it catches the original bug. Ruff and Python compilation pass, and current-head CI passes formatting, lint and the five tests. No remaining blocking findings from the review against the repository standards. Live production rendering was not rerun.

@dazzatronus
dazzatronus merged commit 379dc0a into master Oct 15, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants