返回 ppt-master
animation_config.py
根目录 / skills / ppt-master / scripts / animation_config.py
1 #!/usr/bin/env python3
2 """
3 PPT Master - Animation Config Tool
4
5 Create and validate optional PPTX animation and deterministic Morph sidecars.
6
7 Usage:
8 python3 scripts/animation_config.py scaffold <project_path>
9 python3 scripts/animation_config.py list-groups <project_path>
10 python3 scripts/animation_config.py validate <project_path>
11
12 Examples:
13 python3 scripts/animation_config.py scaffold projects/demo --force
14 python3 scripts/animation_config.py list-groups projects/demo
15 python3 scripts/animation_config.py validate projects/demo
16
17 Dependencies:
18 None (standard library only)
19 """
20
21 from __future__ import annotations
22
23 import argparse
24 import sys
25 from pathlib import Path
26
27 _SCRIPTS_DIR = Path(__file__).resolve().parent
28 if str(_SCRIPTS_DIR) not in sys.path:
29 sys.path.insert(0, str(_SCRIPTS_DIR))
30
31 from console_encoding import configure_utf8_stdio # noqa: E402
32 from svg_to_pptx.animation_config import ( # noqa: E402
33 build_group_listing,
34 load_animation_config,
35 validate_animation_config,
36 validate_animation_config_errors,
37 validate_transition_config,
38 write_scaffold,
39 )
40
41 configure_utf8_stdio()
42
43
44 def build_parser() -> argparse.ArgumentParser:
45 parser = argparse.ArgumentParser(
46 description='Create or validate PPTX motion sidecar configuration.',
47 formatter_class=argparse.RawDescriptionHelpFormatter,
48 )
49 subparsers = parser.add_subparsers(dest='command', required=True)
50
51 scaffold = subparsers.add_parser(
52 'scaffold',
53 help='scan svg_output/*.svg and write animations.json scaffold',
54 )
55 scaffold.add_argument('project_path', help='Project directory')
56 scaffold.add_argument('-o', '--output', default=None, help='Output path; default: <project>/animations.json')
57 scaffold.add_argument('--force', action='store_true', help='Overwrite an existing output file')
58
59 list_groups = subparsers.add_parser(
60 'list-groups',
61 help='print one compact line per slide listing animatable group ids '
62 '(chrome groups excluded); use during planning to avoid reading '
63 'the full scaffold file',
64 )
65 list_groups.add_argument('project_path', help='Project directory')
66
67 validate = subparsers.add_parser(
68 'validate',
69 help='validate animations.json values and project-local references',
70 )
71 validate.add_argument('project_path', help='Project directory')
72 validate.add_argument('-c', '--config', default=None, help='Config path; default: <project>/animations.json')
73
74 return parser
75
76
77 def main(argv: list[str] | None = None) -> int:
78 parser = build_parser()
79 args = parser.parse_args(argv)
80 project_path = Path(args.project_path)
81 if not project_path.exists():
82 print(f'Error: Project path does not exist: {project_path}', file=sys.stderr)
83 return 1
84
85 if args.command == 'scaffold':
86 try:
87 output_path = write_scaffold(
88 project_path,
89 output_path=args.output,
90 force=args.force,
91 )
92 except (FileExistsError, ValueError) as exc:
93 print(f'Error: {exc}', file=sys.stderr)
94 if isinstance(exc, FileExistsError):
95 print('Use --force to overwrite.', file=sys.stderr)
96 return 1
97 print(f'Animation config scaffold written: {output_path}')
98 return 0
99
100 if args.command == 'list-groups':
101 try:
102 lines, anonymous = build_group_listing(project_path)
103 except ValueError as exc:
104 print(f'Error: {exc}', file=sys.stderr)
105 return 1
106 for line in lines:
107 print(line)
108 for warning in anonymous:
109 print(f'Warning: {warning}', file=sys.stderr)
110 return 0
111
112 if args.command == 'validate':
113 try:
114 config = load_animation_config(project_path, args.config)
115 except Exception as exc:
116 print(f'Error: {exc}', file=sys.stderr)
117 return 1
118 if config is None:
119 print('No animations.json found; default animation policy will be used.')
120 return 0
121 errors = list(dict.fromkeys(
122 validate_transition_config(config)
123 + validate_animation_config_errors(config)
124 ))
125 if errors:
126 for error in errors:
127 print(f'Error: {error}', file=sys.stderr)
128 return 1
129 reference_messages = validate_animation_config(project_path, config)
130 reference_warnings = [
131 message for message in reference_messages
132 if ' has no id and cannot be customized in animations.json' in message
133 ]
134 reference_errors = [
135 message for message in reference_messages
136 if message not in reference_warnings
137 ]
138 for warning in reference_warnings:
139 print(f'Warning: {warning}', file=sys.stderr)
140 if reference_errors:
141 for error in reference_errors:
142 print(f'Error: {error}', file=sys.stderr)
143 return 1
144 print('Animation config validated successfully.')
145 return 0
146
147 parser.print_help()
148 return 1
149
150
151 if __name__ == '__main__':
152 raise SystemExit(main())
153
153 lines PYTHON