screenkit 0.0.5 → 0.0.7
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 +2 -2
- data/CHANGELOG.md +12 -4
- data/DOCUMENTATION.md +134 -39
- data/Dockerfile +1 -0
- data/action.yml +140 -0
- data/lib/screenkit/callout/styles/base.rb +16 -0
- data/lib/screenkit/cli/episode.rb +10 -3
- data/lib/screenkit/content_type.rb +1 -1
- data/lib/screenkit/core_ext/json.rb +2 -0
- data/lib/screenkit/core_ext/string.rb +6 -0
- data/lib/screenkit/core_ext.rb +4 -0
- data/lib/screenkit/exporter/demotape.rb +2 -1
- data/lib/screenkit/exporter/episode.rb +21 -8
- data/lib/screenkit/exporter/segment.rb +7 -3
- data/lib/screenkit/exporter/video.rb +7 -2
- data/lib/screenkit/generators/episode/config.yml.erb +8 -103
- data/lib/screenkit/generators/project/.github/screenkit.yml +48 -0
- data/lib/screenkit/generators/project/screenkit.yml +31 -3
- data/lib/screenkit/generators/project.rb +7 -0
- data/lib/screenkit/schemas/refs/tts_builtin.json +5 -1
- data/lib/screenkit/schemas/tts/elevenlabs.json +4 -0
- data/lib/screenkit/schemas/tts/espeak.json +4 -0
- data/lib/screenkit/schemas/tts/say.json +4 -0
- data/lib/screenkit/shell.rb +2 -2
- data/lib/screenkit/tts/base.rb +34 -4
- data/lib/screenkit/tts/eleven_labs.rb +22 -11
- data/lib/screenkit/tts/espeak.rb +11 -11
- data/lib/screenkit/tts/say.rb +9 -9
- data/lib/screenkit/utils.rb +1 -1
- data/lib/screenkit/version.rb +1 -1
- data/lib/screenkit.rb +77 -1
- metadata +8 -6
- data/lib/screen_kit.rb +0 -80
|
@@ -177,6 +177,10 @@ module ScreenKit
|
|
|
177
177
|
log_path:
|
|
178
178
|
end
|
|
179
179
|
|
|
180
|
+
def script_content
|
|
181
|
+
@script_content ||= script_path.read if script_path.file?
|
|
182
|
+
end
|
|
183
|
+
|
|
180
184
|
def create_voiceover(log_path:)
|
|
181
185
|
return if voiceover_path&.file? && !episode.options.overwrite
|
|
182
186
|
return unless script_path.file?
|
|
@@ -185,7 +189,7 @@ module ScreenKit
|
|
|
185
189
|
FileUtils.mkdir_p(voiceover_path.dirname)
|
|
186
190
|
|
|
187
191
|
episode.tts_engine.generate(
|
|
188
|
-
text:
|
|
192
|
+
text: script_content,
|
|
189
193
|
output_path: voiceover_path,
|
|
190
194
|
log_path:
|
|
191
195
|
)
|
|
@@ -294,9 +298,9 @@ module ScreenKit
|
|
|
294
298
|
"#{prefix}-#{index}.{png,#{ContentType.video.join(',')}}"
|
|
295
299
|
).first
|
|
296
300
|
|
|
297
|
-
|
|
301
|
+
return callout_path if callout_path
|
|
298
302
|
|
|
299
|
-
|
|
303
|
+
raise "Callout file not found for #{prefix}-#{index}"
|
|
300
304
|
end
|
|
301
305
|
|
|
302
306
|
def video_callout?(callout_path)
|
|
@@ -9,8 +9,12 @@ module ScreenKit
|
|
|
9
9
|
# The path to the input video file.
|
|
10
10
|
attr_reader :input_path
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
# The path to the log file.
|
|
13
|
+
attr_reader :log_path
|
|
14
|
+
|
|
15
|
+
def initialize(input_path:, log_path: nil)
|
|
13
16
|
@input_path = input_path
|
|
17
|
+
@log_path = log_path
|
|
14
18
|
end
|
|
15
19
|
|
|
16
20
|
def export(output_path)
|
|
@@ -26,7 +30,8 @@ module ScreenKit
|
|
|
26
30
|
"-r", "24",
|
|
27
31
|
"-c:v", "libx264",
|
|
28
32
|
"-y",
|
|
29
|
-
output_path
|
|
33
|
+
output_path,
|
|
34
|
+
log_path:
|
|
30
35
|
end
|
|
31
36
|
end
|
|
32
37
|
end
|
|
@@ -1,106 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
# yaml-language-server: $schema=https://screenkit.dev/schemas/episode.json
|
|
3
3
|
|
|
4
|
-
# The episode title
|
|
5
|
-
# on
|
|
6
|
-
title:
|
|
7
|
-
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# episode configuration can define the content and timing.
|
|
13
|
-
callouts_styles:
|
|
14
|
-
- type: info
|
|
15
|
-
title: "ScreenKit"
|
|
16
|
-
body: "Visit https://github.com/fnando/screenkit to learn more."
|
|
17
|
-
starts_at: 3
|
|
18
|
-
duration: 5
|
|
19
|
-
width: 600
|
|
20
|
-
|
|
21
|
-
# The background music to be played during the episode.
|
|
22
|
-
# When not set, the backtrack will be defined by using the project's
|
|
23
|
-
# `backtrack_dir` configuration, and a track will be randomly selected.
|
|
24
|
-
# To disable the backtrack entirely, use `backtrack: false`.
|
|
25
|
-
# backtrack: resources/backtrack.mp3
|
|
26
|
-
|
|
27
|
-
# Define episode-specific scene configurations.
|
|
28
|
-
# When present, this will have higher precedence over the project's
|
|
29
|
-
# configuration, so you can have different intro/outro for each episode.
|
|
30
|
-
# scenes:
|
|
31
|
-
# intro:
|
|
32
|
-
# # The duration of the intro scene in seconds.
|
|
33
|
-
# duration: 5.5
|
|
34
|
-
#
|
|
35
|
-
# # The fade-in duration in seconds.
|
|
36
|
-
# fade_in: 0
|
|
37
|
-
#
|
|
38
|
-
# # The fade-out duration in seconds.
|
|
39
|
-
# fade_out: 0.5
|
|
40
|
-
#
|
|
41
|
-
# # The background color/image of the intro scene.
|
|
42
|
-
# background: "#100f50"
|
|
43
|
-
#
|
|
44
|
-
# # The title text to be displayed in the intro scene.
|
|
45
|
-
# title:
|
|
46
|
-
# x: 100
|
|
47
|
-
# y: 300
|
|
48
|
-
# font_path: open-sans/OpenSans-ExtraBold.ttf
|
|
49
|
-
# size: 144
|
|
50
|
-
# color: "#ffffff"
|
|
51
|
-
#
|
|
52
|
-
# # The logo to be displayed in the video intro.
|
|
53
|
-
# # Works best with a transparent PNG file in high resolution (at least 2x the
|
|
54
|
-
# # size it'll be displayed).
|
|
55
|
-
# logo:
|
|
56
|
-
# path: images/logo.png
|
|
57
|
-
# x: 100
|
|
58
|
-
# y: 200
|
|
59
|
-
# width: 200
|
|
60
|
-
# height: 34
|
|
61
|
-
#
|
|
62
|
-
# # The sound to be played along with the logo in the intro.
|
|
63
|
-
# # This must correspond to a sound file in the sounds directory, with any
|
|
64
|
-
# # audio extension (e.g. mp3, m4a, wav).
|
|
65
|
-
# sound: sounds/chime.mp3
|
|
66
|
-
#
|
|
67
|
-
# outro:
|
|
68
|
-
# # The duration of the outro scene in seconds.
|
|
69
|
-
# duration: 3.5
|
|
70
|
-
#
|
|
71
|
-
# # The fade-in duration in seconds.
|
|
72
|
-
# fade_in: 0.5
|
|
73
|
-
#
|
|
74
|
-
# # The fade-out duration in seconds.
|
|
75
|
-
# fade_out: 0.5
|
|
76
|
-
#
|
|
77
|
-
# # The background color/image of the outro scene.
|
|
78
|
-
# background: "#100f50"
|
|
79
|
-
#
|
|
80
|
-
# # The sound to be played along with the logo in the outro.
|
|
81
|
-
# sound: sounds/chime.mp3
|
|
82
|
-
#
|
|
83
|
-
# # The logo to be displayed in the video outro.
|
|
84
|
-
# logo:
|
|
85
|
-
# path: images/logo.png
|
|
86
|
-
# x: center
|
|
87
|
-
# y: center
|
|
88
|
-
# width: 500
|
|
89
|
-
#
|
|
90
|
-
# segment:
|
|
91
|
-
# # The duration of the crossover transition between segments in seconds.
|
|
92
|
-
# crossfade_duration: 0.5
|
|
93
|
-
|
|
94
|
-
# Define episode-specific voice configuration.
|
|
95
|
-
# When present, this will have higher precedence over the project's
|
|
96
|
-
# configuration, so you can have different intro/outro segments for each
|
|
97
|
-
# episode.
|
|
98
|
-
# tts:
|
|
99
|
-
# engine: elevenlabs
|
|
100
|
-
# voice_id: 56AoDkrOh6qfVPDXZ7Pt
|
|
101
|
-
# language_code: en
|
|
102
|
-
# voice_settings:
|
|
103
|
-
# speed: 0.9
|
|
104
|
-
# stability: 0.5
|
|
105
|
-
# similarity: 0.75
|
|
106
|
-
# style: 0.0
|
|
4
|
+
# The episode title (displayed in intro scene).
|
|
5
|
+
# Line breaks are inferred based on approximate text width.
|
|
6
|
+
title: <%= options.title.to_yaml[4..] %>
|
|
7
|
+
|
|
8
|
+
# Episode-specific overrides for global configuration.
|
|
9
|
+
# Use an editor with JSON Schema support to see available options and
|
|
10
|
+
# autocomplete.
|
|
11
|
+
# Schema: https://screenkit.dev/schemas/episode.json
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Screenkit
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
inputs:
|
|
7
|
+
episode:
|
|
8
|
+
type: string
|
|
9
|
+
description: "Episode number (e.g. 001)"
|
|
10
|
+
required: true
|
|
11
|
+
tts_preset:
|
|
12
|
+
description: "TTS preset name"
|
|
13
|
+
default: ""
|
|
14
|
+
type: choice
|
|
15
|
+
options:
|
|
16
|
+
- ""
|
|
17
|
+
- say
|
|
18
|
+
- espeak
|
|
19
|
+
- eleven_labs
|
|
20
|
+
- eleven_labs_mp3_192k
|
|
21
|
+
match:
|
|
22
|
+
type: string
|
|
23
|
+
description: "Match pattern for segments (e.g. 001)"
|
|
24
|
+
default: ""
|
|
25
|
+
overwrite:
|
|
26
|
+
type: boolean
|
|
27
|
+
description: "Regenerate files"
|
|
28
|
+
|
|
29
|
+
jobs:
|
|
30
|
+
screenkit:
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
permissions:
|
|
33
|
+
contents: read
|
|
34
|
+
actions: write
|
|
35
|
+
|
|
36
|
+
steps:
|
|
37
|
+
- name: Checkout repository
|
|
38
|
+
uses: actions/checkout@v3
|
|
39
|
+
|
|
40
|
+
- name: Run Screenkit
|
|
41
|
+
uses: fnando/screenkit@v1
|
|
42
|
+
with:
|
|
43
|
+
episode: ${{ github.event.inputs.episode }}
|
|
44
|
+
tts_preset: ${{ github.event.inputs.tts_preset }}
|
|
45
|
+
tts_api_key: ${{ secrets.TTS_API_KEY }}
|
|
46
|
+
overwrite: ${{ github.event.inputs.overwrite }}
|
|
47
|
+
match: ${{ github.event.inputs.match }}
|
|
48
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -84,23 +84,51 @@ watermark:
|
|
|
84
84
|
# Each TTS engine has its own detection mechanism. For instance, say and espeak
|
|
85
85
|
# checks for a binary with the same name. ElevenLabs checks for the presence of
|
|
86
86
|
# `--tts-api-key`.
|
|
87
|
+
#
|
|
88
|
+
# You can have multiple presets for the same engine. Just set a different
|
|
89
|
+
# configuration block using a different `id`. Then, when you're exporting the
|
|
90
|
+
# video, you can use `--tts-preset <id>`. If you don't provide a preset, the
|
|
91
|
+
# first available engine will be used.
|
|
87
92
|
tts:
|
|
88
93
|
# Apple Say TTS engine configuration.
|
|
89
|
-
-
|
|
94
|
+
- id: say
|
|
95
|
+
engine: say
|
|
96
|
+
rate: 150
|
|
97
|
+
enabled: true
|
|
98
|
+
|
|
99
|
+
# Apple Say TTS engine configuration.
|
|
100
|
+
- id: say_pt_br
|
|
101
|
+
engine: say
|
|
102
|
+
voice: "Luciana"
|
|
90
103
|
rate: 150
|
|
91
104
|
enabled: true
|
|
92
105
|
|
|
93
106
|
# eSpeak TTS engine configuration.
|
|
94
|
-
-
|
|
107
|
+
- id: espeak
|
|
108
|
+
engine: espeak
|
|
95
109
|
rate: 150
|
|
96
110
|
voice: en-us
|
|
97
111
|
enabled: true
|
|
98
112
|
|
|
99
113
|
# Eleven Labs TTS engine configuration.
|
|
100
|
-
-
|
|
114
|
+
- id: eleven_labs
|
|
115
|
+
engine: eleven_labs
|
|
116
|
+
enabled: true
|
|
117
|
+
voice_id: 56AoDkrOh6qfVPDXZ7Pt
|
|
118
|
+
language_code: en
|
|
119
|
+
voice_settings:
|
|
120
|
+
speed: 0.9
|
|
121
|
+
stability: 0.5
|
|
122
|
+
similarity: 0.75
|
|
123
|
+
style: 0.0
|
|
124
|
+
|
|
125
|
+
# Eleven Labs TTS engine configuration.
|
|
126
|
+
- id: eleven_labs_mp3_192k
|
|
127
|
+
engine: eleven_labs
|
|
101
128
|
enabled: true
|
|
102
129
|
voice_id: 56AoDkrOh6qfVPDXZ7Pt
|
|
103
130
|
language_code: en
|
|
131
|
+
output_format: mp3_44100_192
|
|
104
132
|
voice_settings:
|
|
105
133
|
speed: 0.9
|
|
106
134
|
stability: 0.5
|
|
@@ -22,6 +22,7 @@ module ScreenKit
|
|
|
22
22
|
def copy_files
|
|
23
23
|
copy_file "screenkit.yml"
|
|
24
24
|
directory "resources", exclude_pattern: /DS_Store/
|
|
25
|
+
directory ".github", exclude_pattern: /DS_Store/
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
def bundle_install
|
|
@@ -32,6 +33,12 @@ module ScreenKit
|
|
|
32
33
|
end
|
|
33
34
|
end
|
|
34
35
|
|
|
36
|
+
def instructions
|
|
37
|
+
cmd = set_color("screenkit episode new --title TITLE", :blue)
|
|
38
|
+
path = set_color(destination_root, :blue)
|
|
39
|
+
say "\nTo create a new episode, run #{cmd} from #{path}"
|
|
40
|
+
end
|
|
41
|
+
|
|
35
42
|
no_commands do
|
|
36
43
|
# Add helper methods here
|
|
37
44
|
end
|
|
@@ -7,9 +7,13 @@
|
|
|
7
7
|
{ "$ref": "../tts/elevenlabs.json" },
|
|
8
8
|
{
|
|
9
9
|
"type": "object",
|
|
10
|
-
"required": ["engine"],
|
|
10
|
+
"required": ["engine", "id"],
|
|
11
11
|
"additionalProperties": true,
|
|
12
12
|
"properties": {
|
|
13
|
+
"id": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "A unique identifier for the tts configuration"
|
|
16
|
+
},
|
|
13
17
|
"engine": {
|
|
14
18
|
"type": "string",
|
|
15
19
|
"description": "The TTS engine to use",
|
data/lib/screenkit/shell.rb
CHANGED
|
@@ -20,9 +20,9 @@ module ScreenKit
|
|
|
20
20
|
!`which #{command}`.strip.empty?
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def run_command(command, *args, log_path: nil)
|
|
23
|
+
def run_command(command, *args, log_path: nil, **)
|
|
24
24
|
args = args.flatten.compact.map(&:to_s)
|
|
25
|
-
stdout, stderr, status = Open3.capture3(command, *args)
|
|
25
|
+
stdout, stderr, status = Open3.capture3(command, *args, **)
|
|
26
26
|
exit_code = status.exitstatus
|
|
27
27
|
|
|
28
28
|
if exit_code&.nonzero?
|
data/lib/screenkit/tts/base.rb
CHANGED
|
@@ -3,18 +3,48 @@
|
|
|
3
3
|
module ScreenKit
|
|
4
4
|
module TTS
|
|
5
5
|
class Base
|
|
6
|
+
require_relative "../core_ext"
|
|
7
|
+
require_relative "../schema_validator"
|
|
8
|
+
|
|
6
9
|
extend SchemaValidator
|
|
7
10
|
|
|
11
|
+
using CoreExt
|
|
12
|
+
|
|
8
13
|
# Additional options for the tts engine.
|
|
9
14
|
attr_reader :options
|
|
10
15
|
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
# The preset name for the tts engine.
|
|
17
|
+
attr_reader :id
|
|
18
|
+
|
|
19
|
+
# The list of segments.
|
|
20
|
+
# This is available so that engines can contextually generate audio, for
|
|
21
|
+
# instance, by providing previous/next text (e.g. Eleven Labs).
|
|
22
|
+
attr_reader :segments
|
|
23
|
+
|
|
24
|
+
# The API key for the tts engine, if applicable.
|
|
25
|
+
attr_reader :api_key
|
|
26
|
+
|
|
27
|
+
# Detects if the tts engine is available.
|
|
28
|
+
def self.available?(**)
|
|
29
|
+
false
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.engine_name
|
|
33
|
+
name.split("::").last.underscore
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def initialize(id: nil, segments: nil, api_key: nil, **options)
|
|
37
|
+
@segments = Array(segments)
|
|
13
38
|
@options = options
|
|
39
|
+
@id = id
|
|
40
|
+
@api_key = api_key
|
|
14
41
|
end
|
|
15
42
|
|
|
16
|
-
def
|
|
17
|
-
|
|
43
|
+
def redact_file(path, text)
|
|
44
|
+
return unless File.file?(path)
|
|
45
|
+
|
|
46
|
+
content = File.read(path).gsub(text, "[REDACTED]")
|
|
47
|
+
File.write(path, content)
|
|
18
48
|
end
|
|
19
49
|
end
|
|
20
50
|
end
|
|
@@ -8,21 +8,16 @@ module ScreenKit
|
|
|
8
8
|
.join("screenkit/schemas/tts/elevenlabs.json")
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def initialize(api_key:, **)
|
|
15
|
-
super(**)
|
|
16
|
-
@api_key = api_key
|
|
11
|
+
def self.available?(api_key: nil, **)
|
|
12
|
+
api_key.to_s.empty?
|
|
17
13
|
end
|
|
18
14
|
|
|
19
|
-
def
|
|
20
|
-
|
|
15
|
+
def all_texts
|
|
16
|
+
@all_texts ||= segments.map(&:script_content)
|
|
21
17
|
end
|
|
22
18
|
|
|
23
19
|
def generate(output_path:, text:, log_path: nil)
|
|
24
|
-
|
|
25
|
-
voice_id = options.delete(:voice_id)
|
|
20
|
+
voice_id = options[:voice_id]
|
|
26
21
|
|
|
27
22
|
if log_path
|
|
28
23
|
File.open(log_path, "w") do |f|
|
|
@@ -32,9 +27,23 @@ module ScreenKit
|
|
|
32
27
|
|
|
33
28
|
require "aitch"
|
|
34
29
|
|
|
30
|
+
Aitch.configure do |config|
|
|
31
|
+
config.logger = Logger.new(log_path) if log_path
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
current_index = all_texts.index { it == text }
|
|
35
|
+
|
|
36
|
+
if current_index
|
|
37
|
+
previous_text = all_texts[current_index - 1]
|
|
38
|
+
next_text = all_texts[current_index + 1]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
params = options.merge(text:, previous_text:, next_text:)
|
|
42
|
+
.except(:voice_id)
|
|
43
|
+
|
|
35
44
|
response = Aitch.post(
|
|
36
45
|
url: "https://api.elevenlabs.io/v1/text-to-speech/#{voice_id}",
|
|
37
|
-
body: JSON.dump(
|
|
46
|
+
body: JSON.dump(params),
|
|
38
47
|
options: {expect: 200},
|
|
39
48
|
headers: {
|
|
40
49
|
"content-type": "application/json",
|
|
@@ -44,6 +53,8 @@ module ScreenKit
|
|
|
44
53
|
)
|
|
45
54
|
|
|
46
55
|
File.binwrite(output_path, response.body)
|
|
56
|
+
ensure
|
|
57
|
+
redact_file(log_path, api_key)
|
|
47
58
|
end
|
|
48
59
|
end
|
|
49
60
|
end
|
data/lib/screenkit/tts/espeak.rb
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
module ScreenKit
|
|
4
4
|
module TTS
|
|
5
5
|
class Espeak < Base
|
|
6
|
-
|
|
6
|
+
extend Shell
|
|
7
7
|
|
|
8
|
-
def self.
|
|
9
|
-
|
|
8
|
+
def self.available?(**)
|
|
9
|
+
command_exist?("espeak")
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def
|
|
13
|
-
|
|
12
|
+
def self.schema_path
|
|
13
|
+
ScreenKit.root_dir.join("screenkit/schemas/tts/espeak.json")
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def generate(text:, output_path:, log_path: nil)
|
|
@@ -18,12 +18,12 @@ module ScreenKit
|
|
|
18
18
|
|
|
19
19
|
{voice: nil, rate: nil}.merge(options) => {voice:, rate:}
|
|
20
20
|
|
|
21
|
-
run_command "espeak",
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
self.class.run_command "espeak",
|
|
22
|
+
(["-v", voice] if voice),
|
|
23
|
+
(["-s", rate] if rate),
|
|
24
|
+
"-w", output_path.sub_ext(".wav"),
|
|
25
|
+
text,
|
|
26
|
+
log_path:
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
end
|
data/lib/screenkit/tts/say.rb
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
module ScreenKit
|
|
4
4
|
module TTS
|
|
5
5
|
class Say < Base
|
|
6
|
-
|
|
6
|
+
extend Shell
|
|
7
7
|
|
|
8
8
|
def self.schema_path
|
|
9
9
|
ScreenKit.root_dir.join("screenkit/schemas/tts/say.json")
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def available?
|
|
13
|
-
|
|
12
|
+
def self.available?(**)
|
|
13
|
+
command_exist?("say")
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def generate(text:, output_path:, log_path: nil)
|
|
@@ -18,12 +18,12 @@ module ScreenKit
|
|
|
18
18
|
|
|
19
19
|
{voice: nil, rate: nil}.merge(options) => {voice:, rate:}
|
|
20
20
|
|
|
21
|
-
run_command "say",
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
self.class.run_command "say",
|
|
22
|
+
(["-v", voice] if voice),
|
|
23
|
+
(["-r", rate] if rate),
|
|
24
|
+
"-o", output_path.sub_ext(".aiff"),
|
|
25
|
+
text,
|
|
26
|
+
log_path:
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
end
|
data/lib/screenkit/utils.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module ScreenKit
|
|
4
4
|
module Utils
|
|
5
|
-
def has_audio?(path)
|
|
5
|
+
def has_audio?(path) # rubocop:disable Naming/PredicatePrefix
|
|
6
6
|
cmd = "ffprobe -v error -select_streams a:0 -show_entries " \
|
|
7
7
|
"stream=codec_type -of default=noprint_wrappers=1:nokey=1"
|
|
8
8
|
`#{cmd} #{path}`.strip == "audio"
|
data/lib/screenkit/version.rb
CHANGED
data/lib/screenkit.rb
CHANGED
|
@@ -1,3 +1,79 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require "thor"
|
|
4
|
+
require "thor/completion"
|
|
5
|
+
require "yaml"
|
|
6
|
+
require "json-schema"
|
|
7
|
+
require "mini_magick"
|
|
8
|
+
require "pathname"
|
|
9
|
+
require "tty-spinner"
|
|
10
|
+
require "etc"
|
|
11
|
+
require "securerandom"
|
|
12
|
+
require "demo_tape/duration"
|
|
13
|
+
|
|
14
|
+
module ScreenKit
|
|
15
|
+
require_relative "screenkit/version"
|
|
16
|
+
require_relative "screenkit/duration"
|
|
17
|
+
require_relative "screenkit/core_ext"
|
|
18
|
+
require_relative "screenkit/content_type"
|
|
19
|
+
require_relative "screenkit/anchor"
|
|
20
|
+
require_relative "screenkit/banner"
|
|
21
|
+
require_relative "screenkit/time_formatter"
|
|
22
|
+
require_relative "screenkit/spacing"
|
|
23
|
+
require_relative "screenkit/watermark"
|
|
24
|
+
require_relative "screenkit/spinner"
|
|
25
|
+
require_relative "screenkit/shell"
|
|
26
|
+
require_relative "screenkit/schema_validator"
|
|
27
|
+
require_relative "screenkit/generators/project"
|
|
28
|
+
require_relative "screenkit/generators/episode"
|
|
29
|
+
require_relative "screenkit/config/base"
|
|
30
|
+
require_relative "screenkit/config/project"
|
|
31
|
+
require_relative "screenkit/config/episode"
|
|
32
|
+
require_relative "screenkit/callout"
|
|
33
|
+
require_relative "screenkit/callout/text_style"
|
|
34
|
+
require_relative "screenkit/callout/styles/base"
|
|
35
|
+
require_relative "screenkit/transition"
|
|
36
|
+
require_relative "screenkit/parallel_processor"
|
|
37
|
+
require_relative "screenkit/cli"
|
|
38
|
+
require_relative "screenkit/cli/base"
|
|
39
|
+
require_relative "screenkit/cli/episode"
|
|
40
|
+
require_relative "screenkit/cli/root"
|
|
41
|
+
require_relative "screenkit/animation_filters"
|
|
42
|
+
require_relative "screenkit/tts/base"
|
|
43
|
+
require_relative "screenkit/path_lookup"
|
|
44
|
+
require_relative "screenkit/sound"
|
|
45
|
+
require_relative "screenkit/utils"
|
|
46
|
+
require_relative "screenkit/logfile"
|
|
47
|
+
require_relative "screenkit/exporter/intro"
|
|
48
|
+
require_relative "screenkit/exporter/outro"
|
|
49
|
+
require_relative "screenkit/exporter/demotape"
|
|
50
|
+
require_relative "screenkit/exporter/episode"
|
|
51
|
+
require_relative "screenkit/exporter/segment"
|
|
52
|
+
require_relative "screenkit/exporter/image"
|
|
53
|
+
require_relative "screenkit/exporter/video"
|
|
54
|
+
|
|
55
|
+
require_files = lambda do |pattern|
|
|
56
|
+
Gem.find_files_from_load_path(pattern).each do |path|
|
|
57
|
+
next if path.include?("test")
|
|
58
|
+
|
|
59
|
+
require(path)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Load all files that may be available as plugins.
|
|
64
|
+
require_files.call("screenkit/callout/styles/*.rb")
|
|
65
|
+
require_files.call("screenkit/tts/*.rb")
|
|
66
|
+
|
|
67
|
+
def self.root_dir
|
|
68
|
+
@root_dir ||= Pathname(__dir__)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Raised when the configuration schema is invalid.
|
|
72
|
+
InvalidConfigSchemaError = Class.new(StandardError)
|
|
73
|
+
|
|
74
|
+
# Raised when a file is not found.
|
|
75
|
+
FileNotFoundError = Class.new(StandardError)
|
|
76
|
+
|
|
77
|
+
# Raised when a file entry is not found in the lookup.
|
|
78
|
+
FileEntryNotFoundError = Class.new(StandardError)
|
|
79
|
+
end
|