## hpr3496 :: How I record HPR Episodes

 https://gitlab.com/norrist/solocast
Sample script.txt
This is a sample script for solocast.
Separate the segments with a blank line

Bulleted lists are OK, but keep the items together by not skipping a line
- Item 1
- Item 2

### Markdown Formatting is OK
But the Formatting gets lost in the script
so you can write show notes in loosely formatted markdown

Don't have more than 1 blank line separating segments

solocast.py
#! /usr/bin/env python3

import click
import os
from shutil import which

script_file = "script.txt"
recording_directory_name = "Recordings"
recording_format = "wav"
script_segments = {}


def test_sox_exists():
    try:
        assert which("sox")
    except AssertionError:
        print("Cant find sox.  Install sox somewhere in your path.")
        exit(1)


def get_recording_file_name(slug):
    return f"{recording_directory_name}/{slug}.{recording_format}"


def project_prep():
    if not os.path.exists(recording_directory_name):
        os.makedirs(recording_directory_name)
    if not os.path.exists(f"{recording_directory_name}/Archive"):
        os.makedirs(f"{recording_directory_name}/Archive")


def wait_for_input():
    click.echo("*" * 40)
    _ = input("Press ENTER to Continue")


def add_slug_text(slug, text):
    script_segments[slug] = text


def recording_exists(slug):
    if os.path.isfile(get_recording_file_name(slug)):
        return True
    return False


def noise_profile_missing():
    if os.path.isfile(f"{recording_directory_name}/noise.prof"):
        return False
    return True


def truncate_audio(slug):
    recording = get_recording_file_name(slug)
    new_recording = f"{recording_directory_name}/{slug}-truncated.{recording_format}"
    click.echo(f"truncating {recording}")

    SOX_CMD = (
        f"sox -V2 {recording}  {new_recording}   silence -l 1 0.1 .1% -1 1.0 .1%   stat"
    )
    click.echo(SOX_CMD)
    os.system(SOX_CMD)
    os.system(
        f" mv -v {recording} {recording_directory_name}/Archive/{slug}.{recording_format}"
    )
    os.rename(new_recording, recording)
    review_audio(slug)


def play_audio(slug):
    recording = get_recording_file_name(slug)
    click.echo(f"Playing {recording}")
    os.system(f"play {recording}")
    review_audio(slug)


def delete_audio(slug):
    recording = get_recording_file_name(slug)
    os.remove(recording)


def review_audio(slug):
    review_menu = ["(p)lay", "(a)ccept", "(r)eccord again", "(t)runcate"]
    click.echo(slug)
    for i in review_menu:
        click.echo(i)
    menu_action = input(">> ")
    if menu_action == "p":
        play_audio(slug)
    elif menu_action == "a":
        exit()
    elif menu_action == "r":
        delete_audio(slug)
        find_and_record_next()
    elif menu_action == "t":
        truncate_audio(slug)
    else:
        review_audio(slug)


def record_audio(slug):
    new_recording = get_recording_file_name(slug)
    click.echo(f"Creating {new_recording}")
    click.echo("press Enter to start then CRTL-C to quit")
    wait_for_input()
    os.system(f"rec {new_recording}")


def record_silent_audio():
    silent_recording = f"{recording_directory_name}/silence.{recording_format}"
    click.echo("RECORD 5 SECONDS OF SILENCE \n" * 5)
    click.echo("press Enter to start")
    wait_for_input()
    os.system(f"rec {silent_recording} trim 0 5")
    os.system(
        f"sox {silent_recording} -n noiseprof {recording_directory_name}/noise.prof"
    )


def load_script():
    linetext = ""
    with open(script_file) as script_file_reader:
        for line in script_file_reader.readlines():

            if not line.strip():

                slug = linetext[:40].title()
                segment_name = "".join(filter(str.isalnum, slug))
                add_slug_text(segment_name, linetext)
                linetext = ""

            else:
                linetext += f"{line}  \n"


def combine_recordings_for_export():
    recording_list = []
    combined_recording = f"{recording_directory_name}/combined.{recording_format}"
    for slug, text in script_segments.items():
        recording = get_recording_file_name(slug)
        recording_list.append(recording)
    recording_list_string = " ".join(recording_list)
    print(recording_list_string)
    SOX_CMD = f"sox -V3 {recording_list_string}  {combined_recording} noisered {recording_directory_name}/noise.prof 0.21 norm -10"
    click.echo(SOX_CMD)
    os.system(SOX_CMD)


def find_and_record_next():
    for slug, text in script_segments.items():
        if recording_exists(slug):
            continue
        click.clear()
        click.echo(slug)
        click.echo("*" * 40)
        click.echo(text)
        click.echo("*" * 40)
        record_audio(slug)
        review_audio(slug)


@click.group()
def cli():
    test_sox_exists()
    pass


@cli.command()
def combine():
    "Combine Segments into single audio file"
    combine_recordings_for_export()


@cli.command()
def record():
    "Record next unrecorded segment"
    if noise_profile_missing():
        record_silent_audio()
    find_and_record_next()


@cli.command()
def silence():
    "Generate noise profile"
    record_silent_audio()



@cli.command()
def review():
    "Print segments"

    for slug, text in script_segments.items():
        click.clear()
        click.echo(slug)
        click.echo("*" * 40)
        click.echo()
        click.echo(text)
        wait_for_input()


if __name__ == "__main__":
    project_prep()
    load_script()
    cli()

