slidemovie 0.2.2__py3-none-any.whl → 0.3.0__py3-none-any.whl
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.
- slidemovie/cli.py +31 -19
- slidemovie/core.py +73 -52
- {slidemovie-0.2.2.dist-info → slidemovie-0.3.0.dist-info}/METADATA +2 -2
- slidemovie-0.3.0.dist-info/RECORD +9 -0
- slidemovie-0.2.2.dist-info/RECORD +0 -9
- {slidemovie-0.2.2.dist-info → slidemovie-0.3.0.dist-info}/WHEEL +0 -0
- {slidemovie-0.2.2.dist-info → slidemovie-0.3.0.dist-info}/entry_points.txt +0 -0
- {slidemovie-0.2.2.dist-info → slidemovie-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {slidemovie-0.2.2.dist-info → slidemovie-0.3.0.dist-info}/top_level.txt +0 -0
slidemovie/cli.py
CHANGED
|
@@ -14,6 +14,7 @@ logging.basicConfig(
|
|
|
14
14
|
)
|
|
15
15
|
logger = logging.getLogger(__name__)
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
def main():
|
|
18
19
|
"""
|
|
19
20
|
Entry point for the slidemovie command-line tool.
|
|
@@ -76,11 +77,18 @@ def main():
|
|
|
76
77
|
)
|
|
77
78
|
|
|
78
79
|
# --- TTS Settings Options (CLI Overrides) ---
|
|
79
|
-
parser.add_argument(
|
|
80
|
+
parser.add_argument(
|
|
81
|
+
"--tts-provider",
|
|
82
|
+
help="TTS Provider (e.g., google, openai)")
|
|
80
83
|
parser.add_argument("--tts-model", help="TTS Model name")
|
|
81
84
|
parser.add_argument("--tts-voice", help="TTS Voice/Speaker setting")
|
|
82
|
-
parser.add_argument(
|
|
83
|
-
|
|
85
|
+
parser.add_argument(
|
|
86
|
+
"--prompt",
|
|
87
|
+
help="Override TTS system prompt (automatically enables prompt usage)")
|
|
88
|
+
parser.add_argument(
|
|
89
|
+
"--no-prompt",
|
|
90
|
+
action="store_true",
|
|
91
|
+
help="Disable TTS system prompt")
|
|
84
92
|
|
|
85
93
|
# --- Other Options ---
|
|
86
94
|
parser.add_argument(
|
|
@@ -89,23 +97,24 @@ def main():
|
|
|
89
97
|
help="Enable debug mode (Verbose logging, etc)."
|
|
90
98
|
)
|
|
91
99
|
|
|
92
|
-
args = parser.parse_args()
|
|
93
|
-
|
|
94
|
-
# Exit if no action is specified
|
|
95
|
-
if not args.pptx and not args.video:
|
|
96
|
-
parser.print_help()
|
|
97
|
-
sys.exit(1)
|
|
98
|
-
|
|
99
100
|
# 1. Initialize Movie instance (Load configuration files)
|
|
100
101
|
try:
|
|
101
102
|
movie = slidemovie.Movie()
|
|
102
103
|
except NameError:
|
|
103
|
-
logger.error(
|
|
104
|
+
logger.error(
|
|
105
|
+
"Movie class is not defined. Make sure to import it correctly.")
|
|
104
106
|
sys.exit(1)
|
|
105
107
|
except Exception as e:
|
|
106
108
|
logger.error(f"Failed to initialize Movie class: {e}")
|
|
107
109
|
sys.exit(1)
|
|
108
110
|
|
|
111
|
+
args = parser.parse_args()
|
|
112
|
+
|
|
113
|
+
# Exit if no action is specified
|
|
114
|
+
if not args.pptx and not args.video:
|
|
115
|
+
parser.print_help()
|
|
116
|
+
sys.exit(1)
|
|
117
|
+
|
|
109
118
|
# 2. Override settings with CLI options
|
|
110
119
|
if args.tts_provider:
|
|
111
120
|
movie.tts_provider = args.tts_provider
|
|
@@ -118,7 +127,9 @@ def main():
|
|
|
118
127
|
movie.tts_use_prompt = True
|
|
119
128
|
if args.no_prompt:
|
|
120
129
|
movie.tts_use_prompt = False
|
|
121
|
-
|
|
130
|
+
if args.filename:
|
|
131
|
+
movie.output_filename = args.filename
|
|
132
|
+
|
|
122
133
|
if args.debug:
|
|
123
134
|
movie.ffmpeg_loglevel = 'info'
|
|
124
135
|
movie.show_skip = True
|
|
@@ -131,13 +142,13 @@ def main():
|
|
|
131
142
|
try:
|
|
132
143
|
if args.sub:
|
|
133
144
|
# Hierarchical Mode (Parent/Child)
|
|
134
|
-
logger.info(
|
|
145
|
+
logger.info(
|
|
146
|
+
f"Configuring subproject paths: {args.project_name}/{args.sub}")
|
|
135
147
|
movie.configure_subproject_paths(
|
|
136
148
|
parent_project_name=args.project_name,
|
|
137
149
|
subproject_name=args.sub,
|
|
138
150
|
source_parent_dir=args.source_dir,
|
|
139
|
-
output_root_dir=args.output_root
|
|
140
|
-
output_filename=args.filename
|
|
151
|
+
output_root_dir=args.output_root
|
|
141
152
|
)
|
|
142
153
|
else:
|
|
143
154
|
# Standard Mode (Flat)
|
|
@@ -145,8 +156,7 @@ def main():
|
|
|
145
156
|
movie.configure_project_paths(
|
|
146
157
|
project_name=args.project_name,
|
|
147
158
|
source_dir=args.source_dir,
|
|
148
|
-
output_root_dir=args.output_root
|
|
149
|
-
output_filename=args.filename
|
|
159
|
+
output_root_dir=args.output_root
|
|
150
160
|
)
|
|
151
161
|
except Exception as e:
|
|
152
162
|
logger.error(f"Failed to configure paths: {e}")
|
|
@@ -162,7 +172,8 @@ def main():
|
|
|
162
172
|
movie.build_slide_pptx()
|
|
163
173
|
logger.info("PPTX generation process finished.")
|
|
164
174
|
if not args.video:
|
|
165
|
-
logger.info(
|
|
175
|
+
logger.info(
|
|
176
|
+
"Please edit the generated PPTX file and run with --video to create the movie.")
|
|
166
177
|
|
|
167
178
|
# Generate Video (--video)
|
|
168
179
|
if args.video:
|
|
@@ -170,8 +181,9 @@ def main():
|
|
|
170
181
|
logger.info("MODE: Build All Video Assets")
|
|
171
182
|
logger.info("=" * 60)
|
|
172
183
|
movie.build_all()
|
|
173
|
-
|
|
184
|
+
|
|
174
185
|
logger.info("All video processes finished.")
|
|
175
186
|
|
|
187
|
+
|
|
176
188
|
if __name__ == "__main__":
|
|
177
189
|
main()
|
slidemovie/core.py
CHANGED
|
@@ -14,6 +14,7 @@ from datetime import datetime
|
|
|
14
14
|
# Configure module logger
|
|
15
15
|
logger = logging.getLogger(__name__)
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
class Movie():
|
|
18
19
|
"""
|
|
19
20
|
A class to automatically generate narration videos based on PowerPoint slides and Markdown notes.
|
|
@@ -55,10 +56,12 @@ class Movie():
|
|
|
55
56
|
- pandoc
|
|
56
57
|
"""
|
|
57
58
|
required_tools = ['ffmpeg', 'ffprobe', 'pandoc']
|
|
58
|
-
missing_tools = [
|
|
59
|
-
|
|
59
|
+
missing_tools = [
|
|
60
|
+
tool for tool in required_tools if not shutil.which(tool)]
|
|
61
|
+
|
|
60
62
|
if missing_tools:
|
|
61
|
-
logger.error(
|
|
63
|
+
logger.error(
|
|
64
|
+
f"Required external commands not found: {', '.join(missing_tools)}")
|
|
62
65
|
logger.error("Please install them before running this tool.")
|
|
63
66
|
sys.exit(1)
|
|
64
67
|
|
|
@@ -86,6 +89,7 @@ class Movie():
|
|
|
86
89
|
show_skip (bool): Whether to log skipped tasks. Default: False.
|
|
87
90
|
max_retry (int): Max retries for TTS API errors. Default: 2.
|
|
88
91
|
output_root (str): Root directory for video output. Default: None.
|
|
92
|
+
output_filename (str): Output video filename (without extension). Default: None (Uses project ID).
|
|
89
93
|
"""
|
|
90
94
|
return {
|
|
91
95
|
# TTS settings
|
|
@@ -116,18 +120,19 @@ class Movie():
|
|
|
116
120
|
"show_skip": False,
|
|
117
121
|
"max_retry": 2,
|
|
118
122
|
|
|
119
|
-
# Output path
|
|
120
|
-
"output_root": None
|
|
123
|
+
# Output path settings (Used if not provided via CLI)
|
|
124
|
+
"output_root": None,
|
|
125
|
+
"output_filename": None
|
|
121
126
|
}
|
|
122
127
|
|
|
123
128
|
def _load_settings(self):
|
|
124
129
|
"""
|
|
125
130
|
Loads settings from JSON files and merges them with defaults.
|
|
126
|
-
|
|
131
|
+
|
|
127
132
|
It looks for configuration in:
|
|
128
133
|
1. ~/.config/slidemovie/config.json
|
|
129
134
|
2. ./config.json
|
|
130
|
-
|
|
135
|
+
|
|
131
136
|
Finally, it sets the configuration values as instance attributes.
|
|
132
137
|
"""
|
|
133
138
|
# 1. Get default settings
|
|
@@ -139,10 +144,11 @@ class Movie():
|
|
|
139
144
|
try:
|
|
140
145
|
os.makedirs(config_dir, exist_ok=True)
|
|
141
146
|
except OSError as e:
|
|
142
|
-
logger.warning(
|
|
147
|
+
logger.warning(
|
|
148
|
+
f"Failed to create config directory {config_dir}: {e}")
|
|
143
149
|
|
|
144
150
|
home_config_path = os.path.join(config_dir, "config.json")
|
|
145
|
-
|
|
151
|
+
|
|
146
152
|
if not os.path.exists(home_config_path):
|
|
147
153
|
# Create default config file if it doesn't exist
|
|
148
154
|
try:
|
|
@@ -162,7 +168,7 @@ class Movie():
|
|
|
162
168
|
|
|
163
169
|
# 3. Process ./config.json (Current directory)
|
|
164
170
|
local_config_path = "./config.json"
|
|
165
|
-
|
|
171
|
+
|
|
166
172
|
if os.path.exists(local_config_path):
|
|
167
173
|
try:
|
|
168
174
|
with open(local_config_path, 'r', encoding='utf-8') as f:
|
|
@@ -173,7 +179,7 @@ class Movie():
|
|
|
173
179
|
logger.warning(f"Failed to load {local_config_path}: {e}")
|
|
174
180
|
|
|
175
181
|
# 4. Set attributes
|
|
176
|
-
|
|
182
|
+
|
|
177
183
|
# Special handling: Convert screen_size from list to tuple
|
|
178
184
|
if "screen_size" in config and isinstance(config["screen_size"], list):
|
|
179
185
|
config["screen_size"] = tuple(config["screen_size"])
|
|
@@ -182,18 +188,16 @@ class Movie():
|
|
|
182
188
|
for key, value in config.items():
|
|
183
189
|
setattr(self, key, value)
|
|
184
190
|
|
|
185
|
-
|
|
186
|
-
|
|
191
|
+
def configure_project_paths(
|
|
192
|
+
self, project_name, source_dir, output_root_dir=None):
|
|
187
193
|
"""
|
|
188
194
|
Configures paths for a standard (flat) project structure.
|
|
189
|
-
|
|
195
|
+
|
|
190
196
|
Args:
|
|
191
197
|
project_name (str): The name/ID of the project.
|
|
192
198
|
source_dir (str): The directory containing source files (.md, .pptx).
|
|
193
|
-
output_root_dir (str, optional): Root directory for video output.
|
|
199
|
+
output_root_dir (str, optional): Root directory for video output.
|
|
194
200
|
Defaults to `self.output_root` or `{source_dir}/movie`.
|
|
195
|
-
output_filename (str, optional): Filename for the output video (without extension).
|
|
196
|
-
Defaults to `project_name`.
|
|
197
201
|
"""
|
|
198
202
|
# Determine output root directory
|
|
199
203
|
target_root = None
|
|
@@ -206,22 +210,25 @@ class Movie():
|
|
|
206
210
|
else:
|
|
207
211
|
target_root = f'{source_dir}/movie'
|
|
208
212
|
is_automatic_path = True
|
|
209
|
-
|
|
213
|
+
|
|
210
214
|
# Expand path
|
|
211
215
|
target_root = os.path.expanduser(target_root)
|
|
212
216
|
|
|
213
217
|
# Handle directory existence
|
|
214
218
|
if is_automatic_path:
|
|
215
|
-
# If the path is automatically determined, create it if it doesn't
|
|
219
|
+
# If the path is automatically determined, create it if it doesn't
|
|
220
|
+
# exist
|
|
216
221
|
if not os.path.isdir(target_root):
|
|
217
222
|
try:
|
|
218
223
|
os.makedirs(target_root, exist_ok=True)
|
|
219
224
|
logger.info(f'Created output directory: {target_root}')
|
|
220
225
|
except OSError as e:
|
|
221
|
-
logger.error(
|
|
226
|
+
logger.error(
|
|
227
|
+
f'Failed to create directory {target_root}: {e}')
|
|
222
228
|
sys.exit(1)
|
|
223
229
|
else:
|
|
224
|
-
# If the path is explicitly specified (CLI or Config), strict check
|
|
230
|
+
# If the path is explicitly specified (CLI or Config), strict check
|
|
231
|
+
# is applied
|
|
225
232
|
if not os.path.isdir(target_root):
|
|
226
233
|
logger.error(f'Directory {target_root} does not exist.')
|
|
227
234
|
sys.exit(1)
|
|
@@ -229,33 +236,34 @@ class Movie():
|
|
|
229
236
|
# Set member variables
|
|
230
237
|
self.source_dir = source_dir
|
|
231
238
|
self.project_id = project_name
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
239
|
+
|
|
240
|
+
# Determine output filename
|
|
241
|
+
# Priority: self.output_filename (Config/CLI) > project_name (Default)
|
|
242
|
+
final_filename = self.output_filename if self.output_filename else project_name
|
|
235
243
|
|
|
236
244
|
# Construct file paths
|
|
237
245
|
self.md_file = f'{self.source_dir}/{project_name}.md'
|
|
238
246
|
self.status_file = f'{self.source_dir}/status.json'
|
|
239
247
|
self.video_length_file = f'{self.source_dir}/video_length.csv'
|
|
240
|
-
|
|
248
|
+
|
|
241
249
|
# Create intermediate/output directories
|
|
242
250
|
self.movie_dir = f'{target_root}/{project_name}'
|
|
243
251
|
if not os.path.isdir(self.movie_dir):
|
|
244
252
|
os.mkdir(self.movie_dir)
|
|
245
253
|
|
|
246
254
|
self.slide_file = f'{self.source_dir}/{project_name}.pptx'
|
|
247
|
-
self.video_file = f'{self.movie_dir}/{
|
|
255
|
+
self.video_file = f'{self.movie_dir}/{final_filename}.mp4'
|
|
248
256
|
|
|
249
|
-
def configure_subproject_paths(
|
|
257
|
+
def configure_subproject_paths(
|
|
258
|
+
self, parent_project_name, subproject_name, source_parent_dir, output_root_dir=None):
|
|
250
259
|
"""
|
|
251
260
|
Configures paths for a nested project structure (Parent Folder -> Child Folder).
|
|
252
|
-
|
|
261
|
+
|
|
253
262
|
Args:
|
|
254
263
|
parent_project_name (str): The name of the parent project.
|
|
255
264
|
subproject_name (str): The name of the subproject (child folder name).
|
|
256
265
|
source_parent_dir (str): The directory containing the parent project folder.
|
|
257
266
|
output_root_dir (str, optional): Root directory for video output.
|
|
258
|
-
output_filename (str, optional): Filename for the output video (without extension).
|
|
259
267
|
"""
|
|
260
268
|
# Determine output root directory
|
|
261
269
|
target_root = None
|
|
@@ -268,64 +276,68 @@ class Movie():
|
|
|
268
276
|
else:
|
|
269
277
|
target_root = f'{source_parent_dir}/movie'
|
|
270
278
|
is_automatic_path = True
|
|
271
|
-
|
|
279
|
+
|
|
272
280
|
# Expand path
|
|
273
281
|
target_root = os.path.expanduser(target_root)
|
|
274
282
|
|
|
275
283
|
# Handle directory existence
|
|
276
284
|
if is_automatic_path:
|
|
277
|
-
# If the path is automatically determined, create it if it doesn't
|
|
285
|
+
# If the path is automatically determined, create it if it doesn't
|
|
286
|
+
# exist
|
|
278
287
|
if not os.path.isdir(target_root):
|
|
279
288
|
try:
|
|
280
289
|
os.makedirs(target_root, exist_ok=True)
|
|
281
290
|
logger.info(f'Created output directory: {target_root}')
|
|
282
291
|
except OSError as e:
|
|
283
|
-
logger.error(
|
|
292
|
+
logger.error(
|
|
293
|
+
f'Failed to create directory {target_root}: {e}')
|
|
284
294
|
sys.exit(1)
|
|
285
295
|
else:
|
|
286
|
-
# If the path is explicitly specified (CLI or Config), strict check
|
|
296
|
+
# If the path is explicitly specified (CLI or Config), strict check
|
|
297
|
+
# is applied
|
|
287
298
|
if not os.path.isdir(target_root):
|
|
288
299
|
logger.error(f'Directory {target_root} does not exist.')
|
|
289
300
|
sys.exit(1)
|
|
290
301
|
|
|
291
302
|
# Source directory is "Parent/Child"
|
|
292
303
|
self.source_dir = f'{source_parent_dir}/{subproject_name}'
|
|
293
|
-
|
|
304
|
+
|
|
294
305
|
# Project ID format: "Parent-Child"
|
|
295
306
|
self.project_id = f'{parent_project_name}-{subproject_name}'
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
307
|
+
|
|
308
|
+
# Determine output filename
|
|
309
|
+
# Priority: self.output_filename (Config/CLI) > self.project_id (Default)
|
|
310
|
+
final_filename = self.output_filename if self.output_filename else self.project_id
|
|
299
311
|
|
|
300
312
|
# Construct file paths
|
|
301
313
|
self.md_file = f'{self.source_dir}/{subproject_name}.md'
|
|
302
314
|
self.status_file = f'{self.source_dir}/status.json'
|
|
303
315
|
self.video_length_file = f'{self.source_dir}/video_length.csv'
|
|
304
|
-
|
|
316
|
+
|
|
305
317
|
# Create output directory hierarchy (movie/parent/child)
|
|
306
318
|
parent_movie_dir = f'{target_root}/{parent_project_name}'
|
|
307
319
|
self.movie_dir = f'{parent_movie_dir}/{subproject_name}'
|
|
308
|
-
|
|
320
|
+
|
|
309
321
|
if not os.path.isdir(parent_movie_dir):
|
|
310
322
|
os.mkdir(parent_movie_dir)
|
|
311
323
|
if not os.path.isdir(self.movie_dir):
|
|
312
324
|
os.mkdir(self.movie_dir)
|
|
313
325
|
|
|
314
326
|
self.slide_file = f'{self.source_dir}/{subproject_name}.pptx'
|
|
315
|
-
self.video_file = f'{self.movie_dir}/{
|
|
327
|
+
self.video_file = f'{self.movie_dir}/{final_filename}.mp4'
|
|
316
328
|
|
|
317
329
|
def build_all(self):
|
|
318
330
|
"""
|
|
319
331
|
Orchestrates the creation of the complete video from Markdown and PPTX files.
|
|
320
|
-
|
|
321
|
-
Note: This does not update the PPTX file from Markdown.
|
|
332
|
+
|
|
333
|
+
Note: This does not update the PPTX file from Markdown.
|
|
322
334
|
Run `build_slide_pptx()` beforehand if necessary.
|
|
323
335
|
"""
|
|
324
336
|
self._check_external_tools()
|
|
325
337
|
if not os.path.isfile(self.md_file):
|
|
326
338
|
logger.error(f'{self.md_file} does not exist.')
|
|
327
339
|
sys.exit(1)
|
|
328
|
-
|
|
340
|
+
|
|
329
341
|
# 1. Generate narration audio from Markdown notes
|
|
330
342
|
self.build_slide_audio()
|
|
331
343
|
# 2. Generate slide images from PPTX
|
|
@@ -375,7 +387,8 @@ class Movie():
|
|
|
375
387
|
audio_state["wav_file"]
|
|
376
388
|
)
|
|
377
389
|
|
|
378
|
-
# Regeneration check (Status mismatch OR Hash mismatch OR File
|
|
390
|
+
# Regeneration check (Status mismatch OR Hash mismatch OR File
|
|
391
|
+
# missing)
|
|
379
392
|
if (audio_status != "generated" or
|
|
380
393
|
saved_notes_hash != current_notes_hash or
|
|
381
394
|
not os.path.isfile(wav_path)):
|
|
@@ -384,7 +397,8 @@ class Movie():
|
|
|
384
397
|
|
|
385
398
|
add_prompt = audio_state.get("additional_prompt", "")
|
|
386
399
|
if norm == "":
|
|
387
|
-
logger.error(
|
|
400
|
+
logger.error(
|
|
401
|
+
f'Error: "::: notes" not found in {slide_id}.')
|
|
388
402
|
sys.exit()
|
|
389
403
|
self._speak_to_wav(
|
|
390
404
|
norm, wav_path, additional_prompt=add_prompt)
|
|
@@ -533,7 +547,8 @@ class Movie():
|
|
|
533
547
|
f"[SKIP] {slide_id} (Video: unchanged/Source:{video_file_src})")
|
|
534
548
|
continue
|
|
535
549
|
|
|
536
|
-
logger.info(
|
|
550
|
+
logger.info(
|
|
551
|
+
f"Converting video: {video_file_src} -> {slide_id}.mp4")
|
|
537
552
|
|
|
538
553
|
# FFmpeg command: Resize + Audio re-encode
|
|
539
554
|
cmd = [
|
|
@@ -580,7 +595,8 @@ class Movie():
|
|
|
580
595
|
png_file = os.path.join(self.movie_dir, f"{slide_id}.png")
|
|
581
596
|
wav_file = os.path.join(self.movie_dir, f"{slide_id}.wav")
|
|
582
597
|
|
|
583
|
-
if not os.path.isfile(
|
|
598
|
+
if not os.path.isfile(
|
|
599
|
+
png_file) or not os.path.isfile(wav_file):
|
|
584
600
|
# Skip if assets are missing
|
|
585
601
|
logger.warning(f"Material missing, skipping: {slide_id}")
|
|
586
602
|
continue
|
|
@@ -1040,7 +1056,8 @@ class Movie():
|
|
|
1040
1056
|
current_config = self._get_build_config()
|
|
1041
1057
|
|
|
1042
1058
|
if stored_config is None:
|
|
1043
|
-
logger.info(
|
|
1059
|
+
logger.info(
|
|
1060
|
+
"No build_config in state file. Applying current settings.")
|
|
1044
1061
|
state["build_config"] = current_config
|
|
1045
1062
|
self._save_audio_state(state)
|
|
1046
1063
|
stored_config = current_config
|
|
@@ -1048,7 +1065,8 @@ class Movie():
|
|
|
1048
1065
|
if stored_config != current_config:
|
|
1049
1066
|
import pprint
|
|
1050
1067
|
logger.error("build_config inconsistency detected.")
|
|
1051
|
-
logger.error(
|
|
1068
|
+
logger.error(
|
|
1069
|
+
"Changing resolution/FPS mid-process is not supported. Aborting.")
|
|
1052
1070
|
logger.error("-" * 40)
|
|
1053
1071
|
logger.error("[Stored Config]")
|
|
1054
1072
|
logger.error(pprint.pformat(stored_config))
|
|
@@ -1064,7 +1082,8 @@ class Movie():
|
|
|
1064
1082
|
|
|
1065
1083
|
# Auto-fill if missing (Migration)
|
|
1066
1084
|
if stored_tts is None:
|
|
1067
|
-
logger.info(
|
|
1085
|
+
logger.info(
|
|
1086
|
+
"No TTS config in state file. Applying current settings.")
|
|
1068
1087
|
state["tts_config"] = current_tts
|
|
1069
1088
|
self._save_audio_state(state)
|
|
1070
1089
|
|
|
@@ -1080,13 +1099,15 @@ class Movie():
|
|
|
1080
1099
|
logger.warning("[Current Config (Now)]")
|
|
1081
1100
|
logger.warning(pprint.pformat(current_tts))
|
|
1082
1101
|
logger.warning("=" * 60)
|
|
1083
|
-
logger.warning(
|
|
1102
|
+
logger.warning(
|
|
1103
|
+
"Generating audio with different settings may result in inconsistent audio in the video.")
|
|
1084
1104
|
|
|
1085
1105
|
while True:
|
|
1086
1106
|
choice = input(
|
|
1087
1107
|
"Select action: 1) Ignore and Continue (Overwrite config) 2) Abort [1/2]: ").strip()
|
|
1088
1108
|
if choice == '1':
|
|
1089
|
-
logger.info(
|
|
1109
|
+
logger.info(
|
|
1110
|
+
"Applying new settings and continuing. Updating state file.")
|
|
1090
1111
|
state["tts_config"] = current_tts
|
|
1091
1112
|
self._save_audio_state(state)
|
|
1092
1113
|
break
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: slidemovie
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Markdown and PowerPoint to narration video generator
|
|
5
5
|
Author: Katsutoshi Seki
|
|
6
6
|
License-Expression: MIT
|
|
@@ -69,7 +69,7 @@ Dynamic: license-file
|
|
|
69
69
|
pip install slidemovie
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
*Note: You also need to install **FFmpeg**, **Pandoc**, **LibreOffice**, and **Poppler**, and set up your **AI API Key** (Google or OpenAI). See the [documentation](https://sekika.github.io/slidemovie/installation
|
|
72
|
+
*Note: You also need to install **FFmpeg**, **Pandoc**, **LibreOffice**, and **Poppler**, and set up your **AI API Key** (Google or OpenAI). See the [documentation](https://sekika.github.io/slidemovie/installation/) for details.*
|
|
73
73
|
|
|
74
74
|
### 2. Create a Project
|
|
75
75
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
slidemovie/__init__.py,sha256=-WEYzm_3B2Db9t-qwLidp6SEU113UpDRxz8DE3Xaeo8,45
|
|
2
|
+
slidemovie/cli.py,sha256=zxP7crk62wTeSD1EEF1JUseLocNqFcHqxTGt8FnXqhA,6038
|
|
3
|
+
slidemovie/core.py,sha256=vES8IYE_N6AHwpjD5gIGPPLr17g28K44xGHiA0ioVCo,53885
|
|
4
|
+
slidemovie-0.3.0.dist-info/licenses/LICENSE,sha256=3i1-4ZoSUnRhEe7bNNHEJ-b6J7YAxQS9WRzq2T-4xmE,1085
|
|
5
|
+
slidemovie-0.3.0.dist-info/METADATA,sha256=r8yr7WU9Gw4aeCHZfhvYnhCkhRT7HGFatr-7wEqR2HE,3592
|
|
6
|
+
slidemovie-0.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
+
slidemovie-0.3.0.dist-info/entry_points.txt,sha256=QKCaqBM90pFuO9XUrGCIjUaQU66HdWU_5h0TJGWxhNY,51
|
|
8
|
+
slidemovie-0.3.0.dist-info/top_level.txt,sha256=fDoWtBH9a9EM1ZygcKZB571mXl3eXBd93VK3SrgrGiQ,11
|
|
9
|
+
slidemovie-0.3.0.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
slidemovie/__init__.py,sha256=-WEYzm_3B2Db9t-qwLidp6SEU113UpDRxz8DE3Xaeo8,45
|
|
2
|
-
slidemovie/cli.py,sha256=D59fkBvl5f3fwu9oSIvNy0VO_E3tNXS48f9zEH4UNx0,5968
|
|
3
|
-
slidemovie/core.py,sha256=PXrQNqPx3oA1GBeaW0R69jXCJjd23VzEOM4qIso3FNM,53577
|
|
4
|
-
slidemovie-0.2.2.dist-info/licenses/LICENSE,sha256=3i1-4ZoSUnRhEe7bNNHEJ-b6J7YAxQS9WRzq2T-4xmE,1085
|
|
5
|
-
slidemovie-0.2.2.dist-info/METADATA,sha256=F3rqyWbbXMRZtYb0_pYkQNYkom7wJOUkmD_DHUO2lHQ,3596
|
|
6
|
-
slidemovie-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
-
slidemovie-0.2.2.dist-info/entry_points.txt,sha256=QKCaqBM90pFuO9XUrGCIjUaQU66HdWU_5h0TJGWxhNY,51
|
|
8
|
-
slidemovie-0.2.2.dist-info/top_level.txt,sha256=fDoWtBH9a9EM1ZygcKZB571mXl3eXBd93VK3SrgrGiQ,11
|
|
9
|
-
slidemovie-0.2.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|