Build Podsqueeze

YESreplaces $8.99/mosaves $107.88/yrback to the verdict

0%0 of 18 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A local episode assistant whose hard problems are keeping every timestamp on the original file's timeline, transcribing a long recording without mangling a word at each chunk boundary, and exporting at the loudness and in the formats the platforms actually publish.

estimated effort weekendthe files for this build are in the project pack

RuntimePython with ffmpeg and a job table in SQLite, one processOriginalsThe master file is read-only and never rewrittenTimelineOne timeline, the original's, for every timestamp in the systemTranscriptionOne interface, a local model by default and an API as an option, returning word-level timesTextOne model call per artefact with the transcript as the only source, each regenerable aloneLoudnessMeasured with a meter implementing the published recommendation, targets read from the platform's own page

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Runs the jobs, the transcription interface and the interface.

    Get it python.org, or your package manager. open ↗

    Verify python3 --version prints 3.12 or higher

  2. installfree

    Why Decoding, silence detection, clip rendering, loudness measurement and encoding all go through it, so a cut-down build will fail halfway through the pipeline.

    Get it Your package manager, or a static build for your platform. open ↗

    Verify A loudness measurement and a silence detection both run on a sample file

  3. installfree locally, pennies per hour hosted

    Why Segment-level timings are not enough: chapters, clips and captions all need word boundaries.

    Get it A local speech model with word timestamps, or an API that returns them.

    Verify A one minute sample returns per-word start and end times

  4. have readyfree

    Why Chunk boundaries, drift and loudness only misbehave on a long recording with real silences, and a three minute sample proves nothing.

    Get it Your own recordings, one over ninety minutes, one with two speakers.

    Verify Both import, and the long one crosses several chunk boundaries

  5. installfree

    Why The only way to know chapters and transcripts exported correctly is to open them somewhere you did not write.

    Get it Any mature player that displays chapter markers and loads a caption file.

    Verify A known good file shows its chapters and captions in it

  6. decidefree

    Why These are published numbers that change, and the build asserts them, so where and when you read them has to be written down.

    Get it Read the platform's current audio and chapter guidance, note the figures and the date, and record both in the repository. open ↗

    Verify The figures appear in configuration and the source and date are in the README

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- episodes(id, title, source_path, sha256, duration_s, sample_rate, channels, container, imported_at) · the source path is read and never written
- jobs(id, episode_id, kind, state, attempts, started_at, finished_at, error) · transcribe, analyse, render
- words(episode_id, ordinal, text, start_s, end_s, speaker, confidence) · times on the original's timeline, always, with no exceptions
- segments(episode_id, ordinal, start_s, end_s, speaker, text) · derived from words and regenerable at any time
- chapters(episode_id, ordinal, start_s, title, source) · source is auto or edited, and an edit is never overwritten by a regeneration
- artefacts(episode_id, kind, model, prompt_version, generated_body, edited_body, generated_at) · title, description, keywords and social posts, each separately regenerable
- clips(id, episode_id, start_s, end_s, reason, rendered_path, integrated_lufs, true_peak_dbtp)
- loudness(episode_id, stage, integrated_lufs, true_peak_dbtp, measured_at) · stage is source, rendered or encoded, because encoding moves the peak

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
DATA_DIRrequired./dataDatabase, working copies and rendered output. Never the masters.
MEDIA_SOURCE_DIRrequired~/RecordingsRead only. The suite hashes everything here after every command.
TRANSCRIBE_BACKENDrequiredlocalLocal model or API. Both return word-level times through the same interface.
TRANSCRIBE_API_KEYsecretoptionalsk-...redactedOnly for the API backend. Audio is uploaded there, so choose deliberately.
TARGET_LUFSrequired-16Copied from the platform's current published figure, with the date recorded in the README.
TRUE_PEAK_CEILING_DBTPrequired-1Also published. Measured on the encoded file, not the intermediate.
CHUNK_OVERLAP_SECONDSrequired5The overlap that lets the stitcher match words instead of trusting a boundary.
WORKDIR_RETENTION_DAYSrequired14Working copies are large and regenerable, so they go first.

The build, in order

  1. Import that never touches the master

    The original is read, hashed and left alone, and every timestamp refers to it.

    1. The one promise about the master, tested rather than stated.

      Files src/import.pytests/test_master_untouched.py

    2. Separate directory, separate lifetime, separate retention.

      Files src/media/decode.py

    3. Every downstream timestamp depends on it.

      Files src/media/timeline.py

    done when · tick each as it passes
    watch out
    • Trimming silence from the working copy before transcription looks like an obvious saving, and it shifts every word time relative to the file you will actually publish, so chapters drift progressively later through the episode and nobody notices until a listener mentions that the markers are off by a minute near the end. Keep one timeline, the original's, and if you must trim for processing then keep the mapping back.
  2. A transcript with word times you can trust

    An hour of audio transcribes without a mangled word at every chunk boundary.

    1. Fixed boundaries land in the middle of words, every time.

      Files src/transcribe/chunk.pytests/test_boundaries.py

    2. The overlap exists so the join can be checked rather than trusted.

      Files src/transcribe/stitch.py

    3. The low confidence minute is the one that ends up quoted.

      Files src/ui/transcript.html

    done when · tick each as it passes
    watch out
    • Splitting an hour of audio into fixed ten minute chunks cuts a word in half at each boundary and produces a mangled token and a timing gap in six places, and because the transcript reads perfectly everywhere else those six places go straight into the show notes. Split on detected silence, overlap the chunks, and de-duplicate the overlap by matching words.
  3. Chapters and notes drawn only from the transcript

    Every chapter starts at a moment that actually exists in the audio.

    1. A chapter that lands mid-word is worse than no chapter.

      Files src/chapters/propose.pytests/test_chapter_times.py

    2. Counts, lengths and title limits are published and they change.

      Files docs/chapter-guidance.md

    3. Regenerating the description must not eat an edited title.

      Files src/artefacts/store.py

    done when · tick each as it passes
    watch out
    • A model asked for chapters returns plausible timestamps that correspond to nothing in the audio, usually suspiciously round numbers, and a listener pressing a chapter lands mid-sentence in the middle of a different topic. Every chapter start must be an actual word start from the transcript, snapped to a silence, and a proposal the audio cannot support is dropped rather than rounded into place.
  4. Clips that begin and end on a sentence

    A rendered clip sounds like something a person cut.

    1. Then fade, so the cut is inaudible rather than merely short.

      Files src/clips/boundaries.pytests/test_clip_edges.py

    2. The working copy exists for transcription, not for output.

      Files src/clips/render.py

    3. With the reason, so the list is worth reading.

      Files src/clips/propose.py

    done when · tick each as it passes
    watch out
    • Cutting at the exact start and end times of a quote clips the first consonant and swallows the tail of the last word, so every clip is amateurish in precisely the same way and it is never obvious why. Expand the boundaries to the silences on either side, add a short fade, and check the rendered file rather than the plan.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more podcasting.