From 19ad38760ed095a8be1a839c576177ee5e646fb7 Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Mon, 24 Nov 2025 09:56:52 -0800 Subject: [PATCH 1/7] WIP --- action.yml | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 action.yml diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..8f990c2 --- /dev/null +++ b/action.yml @@ -0,0 +1,139 @@ +--- +name: ScreenKit Episode +description: Export a screencast episode using Docker +inputs: + episode: + description: "Episode number (e.g. 001)" + required: true + tts_preset_name: + description: "TTS preset name" + default: "" + required: false + overwrite: + description: "Regenerate files" + default: "false" + required: false + match: + description: "Match pattern for segments (e.g. 001)" + default: "" + required: false + tts_api_key: + description: "TTS API key" + required: true + github_token: + description: "GitHub token for cache operations" + required: true + retention: + description: "Retention days for artifacts" + default: 2 + +runs: + using: composite + steps: + - name: Generate cache keys + shell: bash + run: | + VOICEOVER_HASH=$(find episodes/${{ inputs.episode }}-*/scripts/*.txt -type f 2>/dev/null | sort | xargs sha256sum 2>/dev/null | sha256sum | cut -d' ' -f1 || echo "none") + CONTENT_HASH=$(find episodes/${{ inputs.episode }}-*/content/*.* -type f 2>/dev/null | sort | xargs sha256sum 2>/dev/null | sha256sum | cut -d' ' -f1 || echo "none") + + echo "VOICEOVER_CACHE_KEY=episode-voiceover-${{ inputs.episode }}-${VOICEOVER_HASH}" >> $GITHUB_ENV + echo "VOICEOVER_RESTORE_KEYS=episode-voiceover-${{ inputs.episode }}-" >> $GITHUB_ENV + echo "RAW_CACHE_KEY=episode-raw-${{ inputs.episode }}-${CONTENT_HASH}" >> $GITHUB_ENV + echo "RAW_RESTORE_KEYS=episode-raw-${{ inputs.episode }}-" >> $GITHUB_ENV + + - name: Find episode dir + shell: bash + run: | + EPISODE_DIR=$(ls -1d episodes/${{ inputs.episode }}-* | head -n 1) + echo "EPISODE_DIR=$EPISODE_DIR" >> $GITHUB_ENV + + if [[ ! -d "$EPISODE_DIR" ]]; then + echo "Episode directory not found!" + echo "Available episodes:" + ls -1 episodes + exit 1 + fi + + - name: Restore episode voice cache + id: cache-voice + uses: actions/cache/restore@v4 + with: + path: episodes/${{ inputs.episode }}-*/audio + key: ${{ env.VOICEOVER_CACHE_KEY }} + restore-keys: ${{ env.VOICEOVER_RESTORE_KEYS }} + enableCrossOsArchive: true + + - name: Restore raw cache + id: cache-raw + uses: actions/cache/restore@v4 + with: + path: output/${{ inputs.episode }}-*/raw/*.mp4 + key: ${{ env.RAW_CACHE_KEY }} + restore-keys: ${{ env.RAW_RESTORE_KEYS }} + enableCrossOsArchive: true + + - name: Export Episode + shell: bash + id: screenkit + run: | + set -e + docker run \ + --rm \ + --cap-add=SYS_ADMIN \ + --security-opt seccomp=unconfined \ + -e ELEVENLABS_API_KEY="${{ inputs.elevenlabs_api_key }}" \ + -v ${{ github.workspace }}:/source \ + fnando/screenkit:latest \ + export \ + --dir="${{ env.EPISODE_DIR }}" \ + ${{ inputs.match != '' && format('--match {0}', inputs.match) || '' }} \ + ${{ inputs.overwrite == 'true' && '--overwrite' || '--no-overwrite' }} \ + ${{ inputs.tts_preset_name != '' && format('--tts-preset-name {0}', inputs.tts_preset_name) || '' }} + echo "result=true" >> $GITHUB_OUTPUT + + - name: Delete voice cache + if: steps.screenkit.outputs.result == 'true' + shell: bash + run: gh cache delete "${{ env.VOICEOVER_CACHE_KEY }}" || true + env: + GH_TOKEN: ${{ inputs.github_token }} + + - name: Delete raw cache + if: steps.screenkit.outputs.result == 'true' + shell: bash + run: gh cache delete "${{ env.RAW_CACHE_KEY }}" || true + env: + GH_TOKEN: ${{ inputs.github_token }} + + - name: List cache entries + shell: bash + run: | + echo "= Voiceover Cache =" + ls -la episodes/${{ inputs.episode }}-*/audio || true + echo + echo "= Raw Cache =" + ls -la output/${{ inputs.episode }}-*/raw || true + + - name: Save episode voiceover cache + if: steps.screenkit.outputs.result == 'true' + uses: actions/cache/save@v4 + with: + path: episodes/${{ inputs.episode }}-*/audio + key: ${{ env.VOICEOVER_CACHE_KEY }} + enableCrossOsArchive: true + + - name: Save raw recordings cache + if: steps.screenkit.outputs.result == 'true' + uses: actions/cache/save@v4 + with: + path: output/${{ inputs.episode }}-*/raw/*.mp4 + key: ${{ env.RAW_CACHE_KEY }} + enableCrossOsArchive: true + + - name: Upload output artifacts + uses: actions/upload-artifact@v4 + if: always() + with: + name: output + path: output + retention-days: ${{ inputs.retention }} From 6b74148380fb83c34b24a2de82388845839c3e24 Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Mon, 24 Nov 2025 21:15:16 -0800 Subject: [PATCH 2/7] WIP --- action.yml | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/action.yml b/action.yml index 8f990c2..16e51ed 100644 --- a/action.yml +++ b/action.yml @@ -9,6 +9,9 @@ inputs: description: "TTS preset name" default: "" required: false + tts_api_key: + description: "TTS API key" + required: false overwrite: description: "Regenerate files" default: "false" @@ -17,9 +20,6 @@ inputs: description: "Match pattern for segments (e.g. 001)" default: "" required: false - tts_api_key: - description: "TTS API key" - required: true github_token: description: "GitHub token for cache operations" required: true @@ -34,12 +34,12 @@ runs: shell: bash run: | VOICEOVER_HASH=$(find episodes/${{ inputs.episode }}-*/scripts/*.txt -type f 2>/dev/null | sort | xargs sha256sum 2>/dev/null | sha256sum | cut -d' ' -f1 || echo "none") - CONTENT_HASH=$(find episodes/${{ inputs.episode }}-*/content/*.* -type f 2>/dev/null | sort | xargs sha256sum 2>/dev/null | sha256sum | cut -d' ' -f1 || echo "none") + CONTENT_HASH=$(find episodes/${{ inputs.episode }}-*/*/*.* -type f 2>/dev/null | sort | xargs sha256sum 2>/dev/null | sha256sum | cut -d' ' -f1 || echo "none") echo "VOICEOVER_CACHE_KEY=episode-voiceover-${{ inputs.episode }}-${VOICEOVER_HASH}" >> $GITHUB_ENV - echo "VOICEOVER_RESTORE_KEYS=episode-voiceover-${{ inputs.episode }}-" >> $GITHUB_ENV - echo "RAW_CACHE_KEY=episode-raw-${{ inputs.episode }}-${CONTENT_HASH}" >> $GITHUB_ENV - echo "RAW_RESTORE_KEYS=episode-raw-${{ inputs.episode }}-" >> $GITHUB_ENV + echo "VOICEOVER_RESTORE_KEY=episode-voiceover-${{ inputs.episode }}-" >> $GITHUB_ENV + echo "VIDEO_CACHE_KEY=episode-${{ inputs.episode }}-${CONTENT_HASH}" >> $GITHUB_ENV + echo "VIDEO_RESTORE_KEY=episode-${{ inputs.episode }}-" >> $GITHUB_ENV - name: Find episode dir shell: bash @@ -60,16 +60,16 @@ runs: with: path: episodes/${{ inputs.episode }}-*/audio key: ${{ env.VOICEOVER_CACHE_KEY }} - restore-keys: ${{ env.VOICEOVER_RESTORE_KEYS }} + restore-keys: ${{ env.VOICEOVER_RESTORE_KEY }} enableCrossOsArchive: true - - name: Restore raw cache - id: cache-raw + - name: Restore videos cache + id: cache-videos uses: actions/cache/restore@v4 with: - path: output/${{ inputs.episode }}-*/raw/*.mp4 - key: ${{ env.RAW_CACHE_KEY }} - restore-keys: ${{ env.RAW_RESTORE_KEYS }} + path: output/${{ inputs.episode }}-*/videos/*.mp4 + key: ${{ env.VIDEO_CACHE_KEY }} + restore-keys: ${{ env.VIDEO_RESTORE_KEY }} enableCrossOsArchive: true - name: Export Episode @@ -81,14 +81,14 @@ runs: --rm \ --cap-add=SYS_ADMIN \ --security-opt seccomp=unconfined \ - -e ELEVENLABS_API_KEY="${{ inputs.elevenlabs_api_key }}" \ -v ${{ github.workspace }}:/source \ fnando/screenkit:latest \ export \ --dir="${{ env.EPISODE_DIR }}" \ ${{ inputs.match != '' && format('--match {0}', inputs.match) || '' }} \ ${{ inputs.overwrite == 'true' && '--overwrite' || '--no-overwrite' }} \ - ${{ inputs.tts_preset_name != '' && format('--tts-preset-name {0}', inputs.tts_preset_name) || '' }} + ${{ inputs.tts_preset_name != '' && format('--tts-preset-name {0}', inputs.tts_preset_name) || '' }} \ + ${{ inputs.tts_api_key != '' && format('--tts-api-key {0}', inputs.tts_api_key) || '' }} echo "result=true" >> $GITHUB_OUTPUT - name: Delete voice cache @@ -98,10 +98,10 @@ runs: env: GH_TOKEN: ${{ inputs.github_token }} - - name: Delete raw cache + - name: Delete videos cache if: steps.screenkit.outputs.result == 'true' shell: bash - run: gh cache delete "${{ env.RAW_CACHE_KEY }}" || true + run: gh cache delete "${{ env.VIDEO_CACHE_KEY }}" || true env: GH_TOKEN: ${{ inputs.github_token }} @@ -111,8 +111,8 @@ runs: echo "= Voiceover Cache =" ls -la episodes/${{ inputs.episode }}-*/audio || true echo - echo "= Raw Cache =" - ls -la output/${{ inputs.episode }}-*/raw || true + echo "= Videos Cache =" + ls -la output/${{ inputs.episode }}-*/videos || true - name: Save episode voiceover cache if: steps.screenkit.outputs.result == 'true' @@ -122,12 +122,12 @@ runs: key: ${{ env.VOICEOVER_CACHE_KEY }} enableCrossOsArchive: true - - name: Save raw recordings cache + - name: Save video recordings cache if: steps.screenkit.outputs.result == 'true' uses: actions/cache/save@v4 with: - path: output/${{ inputs.episode }}-*/raw/*.mp4 - key: ${{ env.RAW_CACHE_KEY }} + path: output/${{ inputs.episode }}-*/videos/*.mp4 + key: ${{ env.VIDEO_CACHE_KEY }} enableCrossOsArchive: true - name: Upload output artifacts From 2018734daadffbbfe64797889db59b0ab815f8fd Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Mon, 24 Nov 2025 21:42:58 -0800 Subject: [PATCH 3/7] WIP --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 16e51ed..eceb880 100644 --- a/action.yml +++ b/action.yml @@ -83,7 +83,7 @@ runs: --security-opt seccomp=unconfined \ -v ${{ github.workspace }}:/source \ fnando/screenkit:latest \ - export \ + episode export \ --dir="${{ env.EPISODE_DIR }}" \ ${{ inputs.match != '' && format('--match {0}', inputs.match) || '' }} \ ${{ inputs.overwrite == 'true' && '--overwrite' || '--no-overwrite' }} \ From a670cdcf8b00a27d71c4fe89ca85902cd16556f1 Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Mon, 24 Nov 2025 22:08:06 -0800 Subject: [PATCH 4/7] WIP --- action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index eceb880..1f0215c 100644 --- a/action.yml +++ b/action.yml @@ -5,7 +5,7 @@ inputs: episode: description: "Episode number (e.g. 001)" required: true - tts_preset_name: + tts_preset: description: "TTS preset name" default: "" required: false @@ -87,7 +87,7 @@ runs: --dir="${{ env.EPISODE_DIR }}" \ ${{ inputs.match != '' && format('--match {0}', inputs.match) || '' }} \ ${{ inputs.overwrite == 'true' && '--overwrite' || '--no-overwrite' }} \ - ${{ inputs.tts_preset_name != '' && format('--tts-preset-name {0}', inputs.tts_preset_name) || '' }} \ + ${{ inputs.tts_preset != '' && format('--tts-preset {0}', inputs.tts_preset) || '' }} \ ${{ inputs.tts_api_key != '' && format('--tts-api-key {0}', inputs.tts_api_key) || '' }} echo "result=true" >> $GITHUB_OUTPUT From adfcd06c150d3a653ecee7af6d6d12dc671bed40 Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Mon, 24 Nov 2025 22:12:23 -0800 Subject: [PATCH 5/7] WIP --- action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/action.yml b/action.yml index 1f0215c..3374359 100644 --- a/action.yml +++ b/action.yml @@ -80,6 +80,7 @@ runs: docker run \ --rm \ --cap-add=SYS_ADMIN \ + --shm-size=2g \ --security-opt seccomp=unconfined \ -v ${{ github.workspace }}:/source \ fnando/screenkit:latest \ From b278fbfc77d59862d14955e708deec1cd58c5fd4 Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Mon, 24 Nov 2025 22:27:30 -0800 Subject: [PATCH 6/7] WIP --- action.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/action.yml b/action.yml index 3374359..779181f 100644 --- a/action.yml +++ b/action.yml @@ -58,7 +58,7 @@ runs: id: cache-voice uses: actions/cache/restore@v4 with: - path: episodes/${{ inputs.episode }}-*/audio + path: episodes/${{ inputs.episode }}-*/voiceovers key: ${{ env.VOICEOVER_CACHE_KEY }} restore-keys: ${{ env.VOICEOVER_RESTORE_KEY }} enableCrossOsArchive: true @@ -110,7 +110,7 @@ runs: shell: bash run: | echo "= Voiceover Cache =" - ls -la episodes/${{ inputs.episode }}-*/audio || true + ls -la episodes/${{ inputs.episode }}-*/voiceovers || true echo echo "= Videos Cache =" ls -la output/${{ inputs.episode }}-*/videos || true @@ -119,7 +119,7 @@ runs: if: steps.screenkit.outputs.result == 'true' uses: actions/cache/save@v4 with: - path: episodes/${{ inputs.episode }}-*/audio + path: episodes/${{ inputs.episode }}-*/voiceovers key: ${{ env.VOICEOVER_CACHE_KEY }} enableCrossOsArchive: true From d84b647215dd0d302f27593fa08b5eb148b4620c Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Mon, 24 Nov 2025 22:51:24 -0800 Subject: [PATCH 7/7] WIP --- lib/screenkit/generators/project.rb | 1 + .../generators/project/.github/screenkit.yml | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 lib/screenkit/generators/project/.github/screenkit.yml diff --git a/lib/screenkit/generators/project.rb b/lib/screenkit/generators/project.rb index 8bd77e4..32d86f0 100644 --- a/lib/screenkit/generators/project.rb +++ b/lib/screenkit/generators/project.rb @@ -22,6 +22,7 @@ def create_project_dir def copy_files copy_file "screenkit.yml" directory "resources", exclude_pattern: /DS_Store/ + directory ".github", exclude_pattern: /DS_Store/ end def bundle_install diff --git a/lib/screenkit/generators/project/.github/screenkit.yml b/lib/screenkit/generators/project/.github/screenkit.yml new file mode 100644 index 0000000..bd01c60 --- /dev/null +++ b/lib/screenkit/generators/project/.github/screenkit.yml @@ -0,0 +1,48 @@ +--- +name: Screenkit + +on: + workflow_dispatch: + inputs: + episode: + type: string + description: "Episode number (e.g. 001)" + required: true + tts_preset: + description: "TTS preset name" + default: "" + type: choice + options: + - "" + - say + - espeak + - eleven_labs + - eleven_labs_mp3_192k + match: + type: string + description: "Match pattern for segments (e.g. 001)" + default: "" + overwrite: + type: boolean + description: "Regenerate files" + +jobs: + screenkit: + runs-on: ubuntu-latest + permissions: + contents: read + actions: write + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Run Screenkit + uses: fnando/screenkit@v1 + with: + episode: ${{ github.event.inputs.episode }} + tts_preset: ${{ github.event.inputs.tts_preset }} + tts_api_key: ${{ secrets.TTS_API_KEY }} + overwrite: ${{ github.event.inputs.overwrite }} + match: ${{ github.event.inputs.match }} + github_token: ${{ secrets.GITHUB_TOKEN }}