@@ -169,6 +169,23 @@ def generate_narration_via_llm(
169169# Flask app factory
170170# ---------------------------------------------------------------------------
171171
172+ def _find_asset (directory : Path , seg_name : str , seg_id : str , ext : str ) -> Path | None :
173+ """Find an asset file by segment name, then segment ID prefix, then glob."""
174+ if not directory .exists ():
175+ return None
176+ exact = directory / f"{ seg_name } { ext } "
177+ if exact .exists ():
178+ return exact
179+ exact_id = directory / f"{ seg_id } { ext } "
180+ if exact_id .exists ():
181+ return exact_id
182+ for f in directory .glob (f"{ seg_id } -*{ ext } " ):
183+ return f
184+ for f in directory .glob (f"{ seg_id } *{ ext } " ):
185+ return f
186+ return None
187+
188+
172189def create_app (config : Any | None = None ) -> Flask :
173190 app = Flask (
174191 __name__ ,
@@ -277,34 +294,23 @@ def api_segments():
277294 state = load_state (base )
278295 result = []
279296 for seg_id in cfg .segments_all :
280- narration_path = cfg .narration_dir / f"{ seg_id } .md"
281- audio_path = cfg .audio_dir / f"{ seg_id } .mp3"
282-
283- # Try to find the recording with any name prefix
284- rec_found = None
285- if cfg .recordings_dir .exists ():
286- for mp4 in cfg .recordings_dir .glob (f"{ seg_id } *.mp4" ):
287- rec_found = mp4
288- break
289- if not rec_found :
290- for mp4 in cfg .recordings_dir .glob (f"*{ seg_id } *.mp4" ):
291- rec_found = mp4
292- break
297+ seg_name = cfg .resolve_segment_name (seg_id )
298+
299+ narr_found = _find_asset (cfg .narration_dir , seg_name , seg_id , ".md" )
300+ audio_found = _find_asset (cfg .audio_dir , seg_name , seg_id , ".mp3" )
301+ rec_found = _find_asset (cfg .recordings_dir , seg_name , seg_id , ".mp4" )
293302
294303 seg_state = state .get ("segments" , {}).get (seg_id , {})
295304 result .append ({
296305 "id" : seg_id ,
306+ "name" : seg_name ,
297307 "status" : seg_state .get ("status" , "draft" ),
298308 "revision_notes" : seg_state .get ("revision_notes" , "" ),
299- "has_narration" : narration_path .exists (),
300- "has_audio" : audio_path .exists () or bool (
301- list (cfg .audio_dir .glob (f"*{ seg_id } *.mp3" )) if cfg .audio_dir .exists () else []
302- ),
309+ "has_narration" : narr_found is not None ,
310+ "has_audio" : audio_found is not None ,
303311 "has_recording" : rec_found is not None ,
304- "narration_path" : str (narration_path .relative_to (base )) if narration_path .exists () else None ,
305- "audio_path" : str (next (cfg .audio_dir .glob (f"*{ seg_id } *.mp3" )).relative_to (base ))
306- if cfg .audio_dir .exists () and list (cfg .audio_dir .glob (f"*{ seg_id } *.mp3" ))
307- else None ,
312+ "narration_path" : str (narr_found .relative_to (base )) if narr_found else None ,
313+ "audio_path" : str (audio_found .relative_to (base )) if audio_found else None ,
308314 "recording_path" : str (rec_found .relative_to (base )) if rec_found else None ,
309315 "visual_map" : cfg .visual_map .get (seg_id , {}),
310316 })
@@ -317,18 +323,13 @@ def api_get_narration(segment_id: str):
317323 cfg = _cfg ()
318324 if not cfg :
319325 return jsonify ({"error" : "no config" }), 400
320- # Try exact match first, then glob
321- candidates = [
322- cfg .narration_dir / f"{ segment_id } .md" ,
323- ]
324- if cfg .narration_dir .exists ():
325- candidates .extend (cfg .narration_dir .glob (f"*{ segment_id } *.md" ))
326- for p in candidates :
327- if p .exists ():
328- return jsonify ({
329- "text" : p .read_text (encoding = "utf-8" ),
330- "path" : str (p .relative_to (cfg .base_dir )),
331- })
326+ seg_name = cfg .resolve_segment_name (segment_id )
327+ found = _find_asset (cfg .narration_dir , seg_name , segment_id , ".md" )
328+ if found :
329+ return jsonify ({
330+ "text" : found .read_text (encoding = "utf-8" ),
331+ "path" : str (found .relative_to (cfg .base_dir )),
332+ })
332333 return jsonify ({"text" : "" , "path" : None })
333334
334335 @app .route ("/api/narration/<segment_id>" , methods = ["PUT" ])
@@ -338,12 +339,9 @@ def api_put_narration(segment_id: str):
338339 return jsonify ({"error" : "no config" }), 400
339340 data = request .json or {}
340341 text = data .get ("text" , "" )
341- # Find or create narration file
342- target = cfg .narration_dir / f"{ segment_id } .md"
343- if cfg .narration_dir .exists ():
344- for existing in cfg .narration_dir .glob (f"*{ segment_id } *.md" ):
345- target = existing
346- break
342+ seg_name = cfg .resolve_segment_name (segment_id )
343+ found = _find_asset (cfg .narration_dir , seg_name , segment_id , ".md" )
344+ target = found or (cfg .narration_dir / f"{ seg_name } .md" )
347345 cfg .narration_dir .mkdir (parents = True , exist_ok = True )
348346 target .write_text (text , encoding = "utf-8" )
349347 return jsonify ({"ok" : True , "path" : str (target .relative_to (cfg .base_dir ))})
0 commit comments