screenkit 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/docker.yml +44 -0
- data/.github/workflows/ruby-tests.yml +21 -1
- data/Brewfile +5 -0
- data/CHANGELOG.md +7 -0
- data/CONTRIBUTING.md +25 -0
- data/DOCUMENTATION.md +125 -41
- data/Dockerfile +107 -0
- data/lib/screen_kit.rb +15 -16
- data/lib/screenkit/animation_filters.rb +16 -0
- data/lib/screenkit/callout/styles/base.rb +12 -0
- data/lib/screenkit/callout/styles/file_copy.rb +26 -0
- data/lib/screenkit/callout/styles/inline_block.rb +6 -9
- data/lib/screenkit/callout/styles/{default.rb → shadow_block.rb} +9 -11
- data/lib/screenkit/callout.rb +1 -1
- data/lib/screenkit/cli/episode.rb +1 -1
- data/lib/screenkit/config/episode.rb +6 -0
- data/lib/screenkit/config/project.rb +5 -2
- data/lib/screenkit/exporter/demotape.rb +8 -0
- data/lib/screenkit/exporter/episode.rb +37 -17
- data/lib/screenkit/exporter/segment.rb +262 -71
- data/lib/screenkit/generators/episode/callouts/001.yml +12 -0
- data/lib/screenkit/generators/episode/config.yml.erb +8 -8
- data/lib/screenkit/generators/project/screenkit.yml +46 -15
- data/lib/screenkit/schema_validator.rb +1 -1
- data/lib/screenkit/schemas/callout_styles/file_copy.json +8 -0
- data/lib/screenkit/schemas/callout_styles/inline_block.json +20 -0
- data/lib/screenkit/schemas/{callouts/default.json → callout_styles/shadow_block.json} +2 -2
- data/lib/screenkit/schemas/callouts/inline_block.json +20 -11
- data/lib/screenkit/schemas/callouts/shadow_block.json +39 -0
- data/lib/screenkit/schemas/episode.json +6 -43
- data/lib/screenkit/schemas/project.json +4 -5
- data/lib/screenkit/schemas/refs/anchor.json +1 -1
- data/lib/screenkit/schemas/refs/animation.json +1 -1
- data/lib/screenkit/schemas/refs/background.json +1 -1
- data/lib/screenkit/schemas/refs/{callout.json → callout_style.json} +6 -8
- data/lib/screenkit/schemas/refs/color.json +1 -1
- data/lib/screenkit/schemas/refs/demotape.json +1 -1
- data/lib/screenkit/schemas/refs/demotape_themes.json +1 -1
- data/lib/screenkit/schemas/refs/directory.json +1 -1
- data/lib/screenkit/schemas/refs/duration.json +1 -1
- data/lib/screenkit/schemas/refs/intro.json +1 -1
- data/lib/screenkit/schemas/refs/logo.json +1 -1
- data/lib/screenkit/schemas/refs/outro.json +1 -1
- data/lib/screenkit/schemas/refs/position.json +1 -1
- data/lib/screenkit/schemas/refs/scenes.json +1 -1
- data/lib/screenkit/schemas/refs/size.json +1 -1
- data/lib/screenkit/schemas/refs/sound.json +1 -1
- data/lib/screenkit/schemas/refs/spacing.json +1 -1
- data/lib/screenkit/schemas/refs/text_style.json +1 -1
- data/lib/screenkit/schemas/refs/transition.json +1 -1
- data/lib/screenkit/schemas/refs/tts.json +4 -41
- data/lib/screenkit/schemas/refs/tts_builtin.json +23 -0
- data/lib/screenkit/schemas/refs/watermark.json +1 -1
- data/lib/screenkit/schemas/tts/elevenlabs.json +11 -2
- data/lib/screenkit/schemas/tts/espeak.json +26 -0
- data/lib/screenkit/schemas/tts/say.json +11 -1
- data/lib/screenkit/shell.rb +6 -0
- data/lib/screenkit/time_formatter.rb +14 -0
- data/lib/screenkit/tts/base.rb +21 -0
- data/lib/screenkit/tts/eleven_labs.rb +8 -9
- data/lib/screenkit/tts/espeak.rb +30 -0
- data/lib/screenkit/tts/say.rb +5 -6
- data/lib/screenkit/utils.rb +6 -0
- data/lib/screenkit/version.rb +1 -1
- metadata +21 -42
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans-Bold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans-BoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans-ExtraBoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans-Italic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans-Light.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans-LightItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans-Medium.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans-MediumItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans-Regular.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans-SemiBoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_Condensed-Bold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_Condensed-BoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_Condensed-ExtraBold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_Condensed-ExtraBoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_Condensed-Italic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_Condensed-Light.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_Condensed-LightItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_Condensed-Medium.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_Condensed-MediumItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_Condensed-Regular.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_Condensed-SemiBold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_Condensed-SemiBoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_SemiCondensed-Bold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_SemiCondensed-BoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_SemiCondensed-ExtraBold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_SemiCondensed-ExtraBoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_SemiCondensed-Italic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_SemiCondensed-Light.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_SemiCondensed-LightItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_SemiCondensed-Medium.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_SemiCondensed-MediumItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_SemiCondensed-Regular.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_SemiCondensed-SemiBold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/open-sans/OpenSans_SemiCondensed-SemiBoldItalic.ttf +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a4b1ef8eb6ede0220cc3e26f1c038c6ec247a62de276bf5e4df486b01885dcff
|
|
4
|
+
data.tar.gz: 7df82eb1ab87719a2efa7b205c0265a383d93ef574ac30c8ea09d68349df008a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b3741fd30857808cbb6dd16db3b3ab80b401ddfe8c401d508eccb8b37b7cf4f1668858f9d462d3c9d5b30b7c88fb9bf3fd3c7eef6e6afa7c229a60fcf08a5ecb
|
|
7
|
+
data.tar.gz: b8b68adde08a2c44fad33181ef3604e955988cc21d8a2a24a33a39963ac3c437792ce96f3e990d76454e9ee6c6a198d885f868ab828c3c82b85f5db366b32b21
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: docker-image
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
paths:
|
|
8
|
+
- Dockerfile
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
inputs:
|
|
11
|
+
ref:
|
|
12
|
+
description: "Git ref to build the image from"
|
|
13
|
+
required: false
|
|
14
|
+
default: "main"
|
|
15
|
+
|
|
16
|
+
concurrency:
|
|
17
|
+
group: image-workflow
|
|
18
|
+
cancel-in-progress: true
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
build:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
with:
|
|
26
|
+
ref: ${{ github.event.inputs.ref }}
|
|
27
|
+
|
|
28
|
+
- run: >
|
|
29
|
+
echo "IMAGE_TAG=${{ (inputs.ref || github.ref_name) == 'main' &&
|
|
30
|
+
'latest' || (inputs.ref || github.ref_name) }}" >> $GITHUB_ENV
|
|
31
|
+
|
|
32
|
+
- name: Build Docker Image
|
|
33
|
+
run: |
|
|
34
|
+
docker build -t fnando/screenkit:${{ env.IMAGE_TAG }} .
|
|
35
|
+
|
|
36
|
+
- name: Login to Docker Hub
|
|
37
|
+
uses: docker/login-action@v3
|
|
38
|
+
with:
|
|
39
|
+
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
|
40
|
+
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
|
41
|
+
|
|
42
|
+
- name: Push Docker Image
|
|
43
|
+
run: |
|
|
44
|
+
docker push fnando/screenkit:${{ env.IMAGE_TAG }}
|
|
@@ -24,7 +24,7 @@ jobs:
|
|
|
24
24
|
- Gemfile
|
|
25
25
|
|
|
26
26
|
steps:
|
|
27
|
-
- uses: actions/checkout@
|
|
27
|
+
- uses: actions/checkout@v6
|
|
28
28
|
|
|
29
29
|
- uses: actions/cache@v4
|
|
30
30
|
with:
|
|
@@ -36,6 +36,26 @@ jobs:
|
|
|
36
36
|
with:
|
|
37
37
|
ruby-version: ${{ matrix.ruby }}
|
|
38
38
|
|
|
39
|
+
- name: Install system dependencies
|
|
40
|
+
run: |
|
|
41
|
+
# Install ImageMagick and zsh
|
|
42
|
+
sudo apt-get update
|
|
43
|
+
sudo apt-get install -y imagemagick zsh
|
|
44
|
+
|
|
45
|
+
# Download and install FFmpeg 8
|
|
46
|
+
wget --quiet https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz
|
|
47
|
+
tar -xf ffmpeg-master-latest-linux64-gpl.tar.xz
|
|
48
|
+
sudo cp ffmpeg-master-latest-linux64-gpl/bin/ffmpeg /usr/local/bin/
|
|
49
|
+
sudo cp ffmpeg-master-latest-linux64-gpl/bin/ffprobe /usr/local/bin/
|
|
50
|
+
|
|
51
|
+
# Download and install ttyd
|
|
52
|
+
wget --quiet https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.x86_64
|
|
53
|
+
chmod +x ttyd.x86_64
|
|
54
|
+
sudo mv ttyd.x86_64 /usr/local/bin/ttyd
|
|
55
|
+
|
|
56
|
+
# Install ffmpeg-normalize
|
|
57
|
+
pip3 install ffmpeg-normalize
|
|
58
|
+
|
|
39
59
|
- name: Install gem dependencies
|
|
40
60
|
env:
|
|
41
61
|
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
data/Brewfile
ADDED
data/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,13 @@ Prefix your message with one of the following:
|
|
|
11
11
|
- [Security] in case of vulnerabilities.
|
|
12
12
|
-->
|
|
13
13
|
|
|
14
|
+
## v0.0.2
|
|
15
|
+
|
|
16
|
+
- [Added] Add file copy callout style, to copy files to the final output path.
|
|
17
|
+
- [Changed] Copy only two OpenSans font files.
|
|
18
|
+
- [Changed] Rename the default callout to `shadow_block`.
|
|
19
|
+
- [Fixed] Changed all JSON Schema files to use a consistent url.
|
|
20
|
+
|
|
14
21
|
## v0.0.1
|
|
15
22
|
|
|
16
23
|
- [Added] Allow configuring Demo Tape using episode or project configuration.
|
data/CONTRIBUTING.md
CHANGED
|
@@ -32,6 +32,31 @@ by [opening an issue on Github](https://github.com/fnando/screenkit/issues).
|
|
|
32
32
|
When you're ready to make your pull request, follow checklist below to make sure
|
|
33
33
|
your contribution is according to how this project works.
|
|
34
34
|
|
|
35
|
+
### Setting up your environment
|
|
36
|
+
|
|
37
|
+
This project requires the following dependencies:
|
|
38
|
+
|
|
39
|
+
- ffmpeg
|
|
40
|
+
- imagemagick
|
|
41
|
+
- espeak
|
|
42
|
+
- ruby
|
|
43
|
+
- ffmpeg-normalize
|
|
44
|
+
|
|
45
|
+
If you are using macOS, you can install them using [Homebrew](https://brew.sh).
|
|
46
|
+
There's a Brewfile at the root directory with the required dependencies:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
brew bundle install
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
For ffmpeg-normalize, you can use pip:
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
pip install ffmpeg-normalize --user
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Guidelines
|
|
59
|
+
|
|
35
60
|
1. [Fork](https://help.github.com/forking/) screenkit
|
|
36
61
|
2. Create a topic branch - `git checkout -b my_branch`
|
|
37
62
|
3. Make your changes using [descriptive commit messages](#commit-messages)
|
data/DOCUMENTATION.md
CHANGED
|
@@ -215,7 +215,7 @@ Define reusable callout styles:
|
|
|
215
215
|
|
|
216
216
|
```yaml
|
|
217
217
|
callouts:
|
|
218
|
-
|
|
218
|
+
shadow_block:
|
|
219
219
|
background_color: "#ffff00"
|
|
220
220
|
shadow: "#2242d3" # Color string or false
|
|
221
221
|
|
|
@@ -311,7 +311,6 @@ callouts:
|
|
|
311
311
|
|
|
312
312
|
- **Seconds**: `starts_at: 90` (90 seconds)
|
|
313
313
|
- **HH:MM:SS**: `starts_at: "00:01:30"` (1 minute 30 seconds)
|
|
314
|
-
- **Duration**: Always in seconds or time units (`5s`, `2m`, `1h`)
|
|
315
314
|
|
|
316
315
|
---
|
|
317
316
|
|
|
@@ -397,14 +396,15 @@ during the video.
|
|
|
397
396
|
|
|
398
397
|
ScreenKit provides two built-in callout styles:
|
|
399
398
|
|
|
400
|
-
####
|
|
399
|
+
#### Shadow Block Style
|
|
401
400
|
|
|
402
|
-
The
|
|
401
|
+
The shadow block style displays a title and body in a box with optional shadow.
|
|
403
402
|
|
|
404
403
|
```yaml
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
style:
|
|
404
|
+
callout_styles:
|
|
405
|
+
shadow_block: # This key can be anything.
|
|
406
|
+
style: shadow_block # The callout style name (will resolve to
|
|
407
|
+
# a ruby class).
|
|
408
408
|
background_color: "#ffff00" # Background color (hex)
|
|
409
409
|
|
|
410
410
|
# Shadow
|
|
@@ -445,11 +445,11 @@ callouts:
|
|
|
445
445
|
volume: 0.7 # Volume (0.0 to 1.0)
|
|
446
446
|
```
|
|
447
447
|
|
|
448
|
-
|
|
448
|
+
##### Usage in episode
|
|
449
449
|
|
|
450
450
|
```yaml
|
|
451
451
|
callouts:
|
|
452
|
-
- type:
|
|
452
|
+
- type: shadow_block
|
|
453
453
|
title: "ScreenKit"
|
|
454
454
|
body: "Visit https://github.com/fnando/screenkit"
|
|
455
455
|
starts_at: 3
|
|
@@ -463,27 +463,24 @@ similar to syntax highlighting or code comments. Perfect for displaying code
|
|
|
463
463
|
snippets, commands, or short inline text.
|
|
464
464
|
|
|
465
465
|
```yaml
|
|
466
|
-
|
|
467
|
-
code:
|
|
468
|
-
style: inline_block
|
|
466
|
+
callouts_styles:
|
|
467
|
+
code: # This key can be anything.
|
|
468
|
+
style: inline_block # Will resolve to a ruby class.
|
|
469
469
|
background_color: "#000000" # Background color (hex)
|
|
470
470
|
|
|
471
|
-
# Text Style (single style for all text)
|
|
472
471
|
text_style:
|
|
473
472
|
color: "#ffffff"
|
|
474
473
|
size: 40
|
|
475
474
|
font_path: open-sans/OpenSans-ExtraBold.ttf
|
|
476
475
|
|
|
477
476
|
# Layout
|
|
478
|
-
padding: 20
|
|
479
|
-
margin: 100
|
|
480
|
-
anchor: [left, center]
|
|
481
|
-
width: 600
|
|
477
|
+
padding: 20
|
|
478
|
+
margin: 100
|
|
479
|
+
anchor: [left, center]
|
|
480
|
+
width: 600
|
|
482
481
|
|
|
483
|
-
|
|
484
|
-
animation: fade # "fade" or "slide"
|
|
482
|
+
animation: fade
|
|
485
483
|
|
|
486
|
-
# Transitions
|
|
487
484
|
in_transition:
|
|
488
485
|
duration: 0.4
|
|
489
486
|
sound: false
|
|
@@ -493,7 +490,7 @@ callouts:
|
|
|
493
490
|
sound: false
|
|
494
491
|
```
|
|
495
492
|
|
|
496
|
-
|
|
493
|
+
##### Usage in episode
|
|
497
494
|
|
|
498
495
|
```yaml
|
|
499
496
|
callouts:
|
|
@@ -513,14 +510,91 @@ callouts:
|
|
|
513
510
|
duration: 6
|
|
514
511
|
```
|
|
515
512
|
|
|
516
|
-
|
|
513
|
+
#### File Copy Style
|
|
517
514
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
515
|
+
This is not a callout style per se. Instead, you can copy a file to the final
|
|
516
|
+
output directory during episode export. Useful for adding custom assets that may
|
|
517
|
+
be produced outside of ScreenKit.
|
|
518
|
+
|
|
519
|
+
```yaml
|
|
520
|
+
callouts_styles:
|
|
521
|
+
file_copy: # This key can be anything.
|
|
522
|
+
style: file_copy
|
|
523
|
+
|
|
524
|
+
# Layout
|
|
525
|
+
padding: 20
|
|
526
|
+
margin: 100
|
|
527
|
+
anchor: [left, center]
|
|
528
|
+
width: 600
|
|
529
|
+
|
|
530
|
+
animation: fade
|
|
531
|
+
|
|
532
|
+
in_transition:
|
|
533
|
+
duration: 0.4
|
|
534
|
+
sound: false
|
|
535
|
+
|
|
536
|
+
out_transition:
|
|
537
|
+
duration: 0.3
|
|
538
|
+
sound: false
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
##### Usage in episode
|
|
542
|
+
|
|
543
|
+
```yaml
|
|
544
|
+
callouts:
|
|
545
|
+
- type: file_copy
|
|
546
|
+
file_path: images/social_card.png
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
```yaml
|
|
550
|
+
callouts:
|
|
551
|
+
- type: file_copy
|
|
552
|
+
file_path: videos/social_card.mov
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
> [!NOTE]
|
|
556
|
+
>
|
|
557
|
+
> When copying a video file, the video will be used as an overlay, without
|
|
558
|
+
> resizing or repositioning. That means your overlay needs to be exactly
|
|
559
|
+
> 1920x1080 and 24 FPS. If the video has sound, it will be kept on the final
|
|
560
|
+
> output.
|
|
561
|
+
|
|
562
|
+
#### Custom Callout Styles
|
|
563
|
+
|
|
564
|
+
You can create custom callout styles by placing them in the
|
|
565
|
+
`ScreenKit::Callout::Styles` namespace.
|
|
566
|
+
|
|
567
|
+
```ruby
|
|
568
|
+
module ScreenKit
|
|
569
|
+
class Callout
|
|
570
|
+
module Styles
|
|
571
|
+
class SomeStyle < Base
|
|
572
|
+
extend SchemaValidator
|
|
573
|
+
|
|
574
|
+
def self.schema_path
|
|
575
|
+
"some/path/to/your/schema.json"
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
# `source` is the way you search for resources.
|
|
579
|
+
# `output_path` is where you must save the generated callout file.
|
|
580
|
+
# `log_path` is where you can write logs (optional).
|
|
581
|
+
def initialize(source:, output_path:, log_path:, **options)
|
|
582
|
+
self.class.validate!(options)
|
|
583
|
+
|
|
584
|
+
@source = source
|
|
585
|
+
@output_path = output_path
|
|
586
|
+
@log_path = log_path
|
|
587
|
+
@options = options
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
def render
|
|
591
|
+
# Generate the image/video that will be used as a callout.
|
|
592
|
+
end
|
|
593
|
+
end
|
|
594
|
+
end
|
|
595
|
+
end
|
|
596
|
+
end
|
|
597
|
+
```
|
|
524
598
|
|
|
525
599
|
### Anchor Positions
|
|
526
600
|
|
|
@@ -607,28 +681,33 @@ module. Custom engines must implement the `generate` method:
|
|
|
607
681
|
```ruby
|
|
608
682
|
module ScreenKit
|
|
609
683
|
module TTS
|
|
610
|
-
class CustomEngine
|
|
684
|
+
class CustomEngine < Base
|
|
611
685
|
include Shell
|
|
612
|
-
extend SchemaValidator
|
|
613
686
|
|
|
614
687
|
# Optional: Define schema path for validation
|
|
615
688
|
def self.schema_path
|
|
616
689
|
ScreenKit.root_dir.join("screenkit/schemas/tts/custom_engine.json")
|
|
617
690
|
end
|
|
618
691
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
self.class.validate!(@options) if respond_to?(:validate!)
|
|
692
|
+
# This method is required.
|
|
693
|
+
def available?
|
|
694
|
+
enabled? && command_exist?("some-command")
|
|
623
695
|
end
|
|
624
696
|
|
|
697
|
+
# This method is required.
|
|
625
698
|
def generate(text:, output_path:, log_path: nil)
|
|
699
|
+
# Optional: validate options against JSON schema.
|
|
700
|
+
self.class.validate!(options)
|
|
701
|
+
|
|
626
702
|
# Generate audio file from text
|
|
627
703
|
# Write output to output_path
|
|
628
704
|
# Optionally log to log_path
|
|
629
705
|
|
|
630
706
|
# Example implementation:
|
|
631
|
-
#
|
|
707
|
+
# run_command "some-command",
|
|
708
|
+
# "-o", output_path.sub_ext(".wav"),
|
|
709
|
+
# text,
|
|
710
|
+
# log_path:
|
|
632
711
|
end
|
|
633
712
|
end
|
|
634
713
|
end
|
|
@@ -700,8 +779,12 @@ out_transition:
|
|
|
700
779
|
```
|
|
701
780
|
episodes/001-episode-name/
|
|
702
781
|
├── config.yml # Episode configuration
|
|
782
|
+
├── callouts/ # Callout definitions
|
|
783
|
+
│ ├── 001.yml # Callouts that will appear on segment 001
|
|
784
|
+
│ ├── 002.yml
|
|
785
|
+
│ └── ...
|
|
703
786
|
├── content/ # Terminal recordings
|
|
704
|
-
│ ├── 001.tape
|
|
787
|
+
│ ├── 001.tape # Demo Tape files
|
|
705
788
|
│ ├── 002.tape
|
|
706
789
|
│ └── ...
|
|
707
790
|
├── scripts/ # Voiceover scripts
|
|
@@ -718,9 +801,9 @@ episodes/001-episode-name/
|
|
|
718
801
|
└── fonts/
|
|
719
802
|
```
|
|
720
803
|
|
|
721
|
-
###
|
|
804
|
+
### Demo Tape Files
|
|
722
805
|
|
|
723
|
-
ScreenKit uses [
|
|
806
|
+
ScreenKit uses [Demo Tape](https://github.com/fnando/demotape) tape files for
|
|
724
807
|
terminal recordings:
|
|
725
808
|
|
|
726
809
|
```tape
|
|
@@ -879,7 +962,8 @@ When exporting an episode, ScreenKit:
|
|
|
879
962
|
|
|
880
963
|
1. **Validates** project and episode configurations
|
|
881
964
|
2. **Generates voiceovers** from script files (if TTS enabled)
|
|
882
|
-
3. **Renders terminal recordings** from tape files using
|
|
965
|
+
3. **Renders terminal recordings** from tape files using
|
|
966
|
+
[Demo Tape](https://github.com/fnando/demotape)
|
|
883
967
|
4. **Combines segments** with crossfade transitions
|
|
884
968
|
5. **Adds intro/outro** scenes
|
|
885
969
|
6. **Overlays callouts** with animations
|
|
@@ -917,7 +1001,7 @@ be processed).
|
|
|
917
1001
|
### Visuals
|
|
918
1002
|
|
|
919
1003
|
- Use consistent branding across callouts
|
|
920
|
-
- Test callout
|
|
1004
|
+
- Test callout formats with `screenkit callout` command
|
|
921
1005
|
- PNG images with transparency work best for logos and watermarks
|
|
922
1006
|
|
|
923
1007
|
### Organization
|
|
@@ -953,7 +1037,7 @@ bundle exec screenkit ...
|
|
|
953
1037
|
|
|
954
1038
|
**TTS not working:**
|
|
955
1039
|
|
|
956
|
-
- For ElevenLabs: Set `--voice-api-key`
|
|
1040
|
+
- For ElevenLabs: Set `--voice-api-key`
|
|
957
1041
|
- For macOS `say`: Verify voice name with `say -v ?`
|
|
958
1042
|
|
|
959
1043
|
---
|
data/Dockerfile
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Stage 1: Download and extract fonts
|
|
2
|
+
FROM --platform=linux/amd64 alpine:latest AS fonts
|
|
3
|
+
RUN apk add --no-cache curl unzip
|
|
4
|
+
RUN mkdir /fonts && \
|
|
5
|
+
curl -sSL -o JetBrainsMono.zip https://github.com/ryanoasis/nerd-fonts/releases/download/v3.4.0/JetBrainsMono.zip && \
|
|
6
|
+
unzip -j JetBrainsMono.zip 'JetBrainsMonoNerdFontPropo-*.ttf' -d /fonts
|
|
7
|
+
|
|
8
|
+
# Stage 2: Download binaries
|
|
9
|
+
FROM --platform=linux/amd64 alpine:latest AS binaries
|
|
10
|
+
ARG SLIDES_VERSION=0.9.0
|
|
11
|
+
ARG TTYD_VERSION=1.7.7
|
|
12
|
+
ARG LL_VERSION=0.0.11
|
|
13
|
+
ARG BAT_VERSION=0.26.0
|
|
14
|
+
RUN apk add --no-cache curl
|
|
15
|
+
RUN mkdir /bin-download && cd /bin-download && \
|
|
16
|
+
curl -sSL https://github.com/maaslalani/slides/releases/download/v${SLIDES_VERSION}/slides_${SLIDES_VERSION}_linux_amd64.tar.gz | tar xz && \
|
|
17
|
+
curl -sSL https://github.com/tsl0922/ttyd/releases/download/${TTYD_VERSION}/ttyd.x86_64 > ttyd && \
|
|
18
|
+
curl -sSL https://github.com/fnando/ll/releases/download/v${LL_VERSION}/ll-x86_64-unknown-linux-gnu.tar.gz | tar xz && \
|
|
19
|
+
curl -sSL https://github.com/sharkdp/bat/releases/download/v${BAT_VERSION}/bat-v${BAT_VERSION}-x86_64-unknown-linux-musl.tar.gz | tar xz && \
|
|
20
|
+
mv bat-v${BAT_VERSION}-x86_64-unknown-linux-musl/bat . && \
|
|
21
|
+
chmod +x slides ttyd ll bat
|
|
22
|
+
|
|
23
|
+
# Stage 3: Final image
|
|
24
|
+
FROM --platform=linux/amd64 ruby:3.4-alpine
|
|
25
|
+
|
|
26
|
+
# Install runtime dependencies and build tools
|
|
27
|
+
RUN apk add --no-cache \
|
|
28
|
+
--repository=http://dl-cdn.alpinelinux.org/alpine/edge/main \
|
|
29
|
+
--repository=http://dl-cdn.alpinelinux.org/alpine/edge/community \
|
|
30
|
+
bash \
|
|
31
|
+
bash-completion \
|
|
32
|
+
build-base \
|
|
33
|
+
ca-certificates \
|
|
34
|
+
chromium \
|
|
35
|
+
chromium-chromedriver \
|
|
36
|
+
curl \
|
|
37
|
+
fish \
|
|
38
|
+
ffmpeg \
|
|
39
|
+
font-liberation \
|
|
40
|
+
font-noto \
|
|
41
|
+
font-noto-emoji \
|
|
42
|
+
freetype \
|
|
43
|
+
git \
|
|
44
|
+
gtk+3.0 \
|
|
45
|
+
harfbuzz \
|
|
46
|
+
imagemagick \
|
|
47
|
+
jq \
|
|
48
|
+
less \
|
|
49
|
+
mesa-gl \
|
|
50
|
+
nss \
|
|
51
|
+
python3 \
|
|
52
|
+
py3-pip \
|
|
53
|
+
py3-virtualenv \
|
|
54
|
+
sudo \
|
|
55
|
+
ttf-dejavu \
|
|
56
|
+
ttf-freefont \
|
|
57
|
+
udev \
|
|
58
|
+
zsh \
|
|
59
|
+
&& fc-cache -f
|
|
60
|
+
|
|
61
|
+
ARG USER=screenkit
|
|
62
|
+
ENV TERM=xterm-256color
|
|
63
|
+
ENV PATH="/venv/bin:/source/bin:/${USER}/bin:$PATH"
|
|
64
|
+
ENV CHROME_BIN=/usr/bin/chromium-browser
|
|
65
|
+
ENV CHROME_PATH=/usr/lib/chromium/
|
|
66
|
+
|
|
67
|
+
# Copy binaries and fonts from builder stages
|
|
68
|
+
COPY --from=binaries /bin-download/slides /usr/local/bin/slides
|
|
69
|
+
COPY --from=binaries /bin-download/ttyd /usr/local/bin/ttyd
|
|
70
|
+
COPY --from=binaries /bin-download/ll /usr/local/bin/ll
|
|
71
|
+
COPY --from=binaries /bin-download/bat /usr/local/bin/bat
|
|
72
|
+
COPY --from=fonts /fonts /usr/local/share/fonts
|
|
73
|
+
|
|
74
|
+
# Update font cache
|
|
75
|
+
RUN fc-cache -f
|
|
76
|
+
|
|
77
|
+
# Create user
|
|
78
|
+
RUN adduser -D -h /${USER} -s /bin/zsh -u 1001 ${USER} \
|
|
79
|
+
&& chown -R ${USER}:${USER} /${USER} \
|
|
80
|
+
&& echo "${USER} ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/${USER} \
|
|
81
|
+
&& chmod 0440 /etc/sudoers.d/${USER}
|
|
82
|
+
|
|
83
|
+
RUN mkdir -p /venv && chown -R ${USER}:${USER} /venv
|
|
84
|
+
RUN mkdir -p /${USER}-local && chown -R ${USER}:${USER} /${USER}-local
|
|
85
|
+
|
|
86
|
+
# Install screenkit gem
|
|
87
|
+
RUN gem install screenkit && \
|
|
88
|
+
mkdir -p /usr/share/bash-completion/completions && \
|
|
89
|
+
mkdir -p /usr/share/zsh/site-functions && \
|
|
90
|
+
mkdir -p /usr/share/fish/vendor_completions.d && \
|
|
91
|
+
screenkit completion --shell bash > /usr/share/bash-completion/completions/screenkit && \
|
|
92
|
+
screenkit completion --shell zsh > /usr/share/zsh/site-functions/_screenkit && \
|
|
93
|
+
screenkit completion --shell fish > /usr/share/fish/vendor_completions.d/screenkit.fish && \
|
|
94
|
+
echo 'autoload -Uz compinit && compinit' >> /etc/zsh/zshrc && \
|
|
95
|
+
echo 'source /usr/share/bash-completion/bash_completion' >> /etc/bash/bashrc && \
|
|
96
|
+
apk del build-base
|
|
97
|
+
|
|
98
|
+
USER ${USER}
|
|
99
|
+
WORKDIR /${USER}
|
|
100
|
+
|
|
101
|
+
# Create Python virtual environment
|
|
102
|
+
RUN python3 -m venv /venv
|
|
103
|
+
RUN /venv/bin/pip install ffmpeg-normalize
|
|
104
|
+
|
|
105
|
+
WORKDIR /source
|
|
106
|
+
|
|
107
|
+
ENTRYPOINT [ "screenkit" ]
|
data/lib/screen_kit.rb
CHANGED
|
@@ -19,6 +19,7 @@ module ScreenKit
|
|
|
19
19
|
require_relative "screenkit/content_type"
|
|
20
20
|
require_relative "screenkit/anchor"
|
|
21
21
|
require_relative "screenkit/banner"
|
|
22
|
+
require_relative "screenkit/time_formatter"
|
|
22
23
|
require_relative "screenkit/spacing"
|
|
23
24
|
require_relative "screenkit/watermark"
|
|
24
25
|
require_relative "screenkit/spinner"
|
|
@@ -31,17 +32,15 @@ module ScreenKit
|
|
|
31
32
|
require_relative "screenkit/config/episode"
|
|
32
33
|
require_relative "screenkit/callout"
|
|
33
34
|
require_relative "screenkit/callout/text_style"
|
|
35
|
+
require_relative "screenkit/callout/styles/base"
|
|
34
36
|
require_relative "screenkit/transition"
|
|
35
37
|
require_relative "screenkit/parallel_processor"
|
|
36
|
-
require_relative "screenkit/callout/styles/base"
|
|
37
|
-
require_relative "screenkit/callout/styles/default"
|
|
38
38
|
require_relative "screenkit/cli"
|
|
39
39
|
require_relative "screenkit/cli/base"
|
|
40
40
|
require_relative "screenkit/cli/episode"
|
|
41
41
|
require_relative "screenkit/cli/root"
|
|
42
|
-
require_relative "screenkit/tts/say"
|
|
43
|
-
require_relative "screenkit/tts/eleven_labs"
|
|
44
42
|
require_relative "screenkit/animation_filters"
|
|
43
|
+
require_relative "screenkit/tts/base"
|
|
45
44
|
require_relative "screenkit/path_lookup"
|
|
46
45
|
require_relative "screenkit/sound"
|
|
47
46
|
require_relative "screenkit/utils"
|
|
@@ -54,6 +53,18 @@ module ScreenKit
|
|
|
54
53
|
require_relative "screenkit/exporter/image"
|
|
55
54
|
require_relative "screenkit/exporter/video"
|
|
56
55
|
|
|
56
|
+
require_files = lambda do |pattern|
|
|
57
|
+
Gem.find_files_from_load_path(pattern).each do |path|
|
|
58
|
+
next if path.include?("test")
|
|
59
|
+
|
|
60
|
+
require(path)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Load all files that may be available as plugins.
|
|
65
|
+
require_files.call("screenkit/callout/styles/*.rb")
|
|
66
|
+
require_files.call("screenkit/tts/*.rb")
|
|
67
|
+
|
|
57
68
|
def self.root_dir
|
|
58
69
|
@root_dir ||= Pathname(__dir__)
|
|
59
70
|
end
|
|
@@ -66,16 +77,4 @@ module ScreenKit
|
|
|
66
77
|
|
|
67
78
|
# Raised when a file entry is not found in the lookup.
|
|
68
79
|
FileEntryNotFoundError = Class.new(StandardError)
|
|
69
|
-
|
|
70
|
-
require_files = lambda do |pattern|
|
|
71
|
-
Gem.find_files_from_load_path(pattern).each do |path|
|
|
72
|
-
next if path.include?("test")
|
|
73
|
-
|
|
74
|
-
require(path)
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# Load all files that may be available as plugins.
|
|
79
|
-
require_files.call("screenkit/callout/styles/*.rb")
|
|
80
|
-
require_files.call("screenkit/callout/tts/*.rb")
|
|
81
80
|
end
|
|
@@ -110,5 +110,21 @@ module ScreenKit
|
|
|
110
110
|
|
|
111
111
|
{video: filters, out_start:}
|
|
112
112
|
end
|
|
113
|
+
|
|
114
|
+
def video
|
|
115
|
+
filters = []
|
|
116
|
+
|
|
117
|
+
# For video callouts:
|
|
118
|
+
# Add transparent padding at start to delay, then overlay
|
|
119
|
+
filters <<
|
|
120
|
+
"[#{callout_index}:v]tpad=start_duration=#{starts_at}:" \
|
|
121
|
+
"color=black@0.0[callout#{index}_delayed]"
|
|
122
|
+
|
|
123
|
+
filters <<
|
|
124
|
+
"[#{input_stream}][callout#{index}_delayed]overlay=x=#{x}:y=#{y}:" \
|
|
125
|
+
"eof_action=pass[#{output_stream}]"
|
|
126
|
+
|
|
127
|
+
{video: filters, out_start:}
|
|
128
|
+
end
|
|
113
129
|
end
|
|
114
130
|
end
|
|
@@ -4,6 +4,18 @@ module ScreenKit
|
|
|
4
4
|
class Callout
|
|
5
5
|
module Styles
|
|
6
6
|
class Base
|
|
7
|
+
attr_reader :source, :output_path, :log_path
|
|
8
|
+
attr_accessor :options
|
|
9
|
+
|
|
10
|
+
extend SchemaValidator
|
|
11
|
+
|
|
12
|
+
def initialize(source:, output_path:, log_path: nil, **options)
|
|
13
|
+
@source = source
|
|
14
|
+
@output_path = output_path
|
|
15
|
+
@log_path = log_path
|
|
16
|
+
@options = options
|
|
17
|
+
end
|
|
18
|
+
|
|
7
19
|
def text_wrap(text, max_width:, font_size:)
|
|
8
20
|
words = text.to_s.split(/\s+/)
|
|
9
21
|
width_factor = 0.6
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ScreenKit
|
|
4
|
+
class Callout
|
|
5
|
+
module Styles
|
|
6
|
+
class FileCopy < Base
|
|
7
|
+
def self.schema_path
|
|
8
|
+
ScreenKit.root_dir
|
|
9
|
+
.join("screenkit/schemas/callout_styles/file_copy.json")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def initialize(source:, **kwargs)
|
|
13
|
+
self.class.validate!(kwargs)
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def render
|
|
18
|
+
ext = File.extname(options[:file_path])
|
|
19
|
+
FileUtils.mkdir_p(File.dirname(output_path))
|
|
20
|
+
FileUtils.cp source.search(options[:file_path]),
|
|
21
|
+
output_path.sub_ext(ext)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|