pykara 0.0.1__tar.gz
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.
- pykara-0.0.1/.editorconfig +4 -0
- pykara-0.0.1/.gitattributes +2 -0
- pykara-0.0.1/.github/workflows/ci.yml +103 -0
- pykara-0.0.1/.github/workflows/package.yml +46 -0
- pykara-0.0.1/.github/workflows/publish.yml +70 -0
- pykara-0.0.1/.gitignore +36 -0
- pykara-0.0.1/.rumdl.toml +7 -0
- pykara-0.0.1/PKG-INFO +107 -0
- pykara-0.0.1/README.md +76 -0
- pykara-0.0.1/bridge/pykara.lua +243 -0
- pykara-0.0.1/docs/directives/char-scope.md +41 -0
- pykara-0.0.1/docs/directives/interpolation.md +38 -0
- pykara-0.0.1/docs/directives/line-scope.md +37 -0
- pykara-0.0.1/docs/directives/modifiers.md +172 -0
- pykara-0.0.1/docs/directives/scopes.md +16 -0
- pykara-0.0.1/docs/directives/setup-scope.md +23 -0
- pykara-0.0.1/docs/directives/syllable-scope.md +47 -0
- pykara-0.0.1/docs/directives/types.md +55 -0
- pykara-0.0.1/docs/directives/word-scope.md +36 -0
- pykara-0.0.1/docs/directives.md +55 -0
- pykara-0.0.1/docs/helpers/color.md +65 -0
- pykara-0.0.1/docs/helpers/memory.md +29 -0
- pykara-0.0.1/docs/helpers/motion.md +191 -0
- pykara-0.0.1/docs/helpers/palette.md +30 -0
- pykara-0.0.1/docs/helpers/relayer.md +17 -0
- pykara-0.0.1/docs/helpers/repeat.md +43 -0
- pykara-0.0.1/docs/helpers/retime.md +198 -0
- pykara-0.0.1/docs/helpers/scale.md +72 -0
- pykara-0.0.1/docs/helpers/timeline.md +80 -0
- pykara-0.0.1/docs/helpers.md +80 -0
- pykara-0.0.1/docs/index.md +27 -0
- pykara-0.0.1/pyproject.toml +122 -0
- pykara-0.0.1/src/pykara/__init__.py +26 -0
- pykara-0.0.1/src/pykara/ass/__init__.py +26 -0
- pykara-0.0.1/src/pykara/ass/parser.py +353 -0
- pykara-0.0.1/src/pykara/ass/time.py +78 -0
- pykara-0.0.1/src/pykara/ass/types.py +141 -0
- pykara-0.0.1/src/pykara/ass/writer.py +139 -0
- pykara-0.0.1/src/pykara/cli.py +125 -0
- pykara-0.0.1/src/pykara/directive/__init__.py +51 -0
- pykara-0.0.1/src/pykara/directive/parser.py +393 -0
- pykara-0.0.1/src/pykara/directive/types.py +168 -0
- pykara-0.0.1/src/pykara/directive/validator.py +231 -0
- pykara-0.0.1/src/pykara/engine/__init__.py +20 -0
- pykara-0.0.1/src/pykara/engine/collector.py +166 -0
- pykara-0.0.1/src/pykara/engine/context_builder.py +68 -0
- pykara-0.0.1/src/pykara/engine/evaluator.py +31 -0
- pykara-0.0.1/src/pykara/engine/execution_runtime.py +209 -0
- pykara-0.0.1/src/pykara/engine/expression_catalog.py +228 -0
- pykara-0.0.1/src/pykara/engine/expression_proxies.py +152 -0
- pykara-0.0.1/src/pykara/engine/fbf_slot.py +34 -0
- pykara-0.0.1/src/pykara/engine/interpolator.py +91 -0
- pykara-0.0.1/src/pykara/engine/line_runtime_factory.py +70 -0
- pykara-0.0.1/src/pykara/engine/loop.py +190 -0
- pykara-0.0.1/src/pykara/engine/output.py +21 -0
- pykara-0.0.1/src/pykara/engine/preflight.py +163 -0
- pykara-0.0.1/src/pykara/engine/protocols.py +256 -0
- pykara-0.0.1/src/pykara/engine/retime_state.py +114 -0
- pykara-0.0.1/src/pykara/engine/rng.py +43 -0
- pykara-0.0.1/src/pykara/engine/runner.py +296 -0
- pykara-0.0.1/src/pykara/engine/runtime_execution.py +37 -0
- pykara-0.0.1/src/pykara/engine/scope_registry.py +63 -0
- pykara-0.0.1/src/pykara/engine/variable_registry.py +86 -0
- pykara-0.0.1/src/pykara/engine/variable_resolver.py +129 -0
- pykara-0.0.1/src/pykara/exceptions.py +35 -0
- pykara-0.0.1/src/pykara/helpers/__init__.py +44 -0
- pykara-0.0.1/src/pykara/helpers/color.py +109 -0
- pykara-0.0.1/src/pykara/helpers/memory.py +41 -0
- pykara-0.0.1/src/pykara/helpers/motion.py +23 -0
- pykara-0.0.1/src/pykara/helpers/motion_base.py +63 -0
- pykara-0.0.1/src/pykara/helpers/motion_fbf.py +155 -0
- pykara-0.0.1/src/pykara/helpers/motion_shad.py +182 -0
- pykara-0.0.1/src/pykara/helpers/palette.py +382 -0
- pykara-0.0.1/src/pykara/helpers/relayer.py +23 -0
- pykara-0.0.1/src/pykara/helpers/repeat.py +77 -0
- pykara-0.0.1/src/pykara/helpers/retime.py +31 -0
- pykara-0.0.1/src/pykara/helpers/retime_presets.py +221 -0
- pykara-0.0.1/src/pykara/helpers/retime_targets.py +138 -0
- pykara-0.0.1/src/pykara/helpers/scale.py +63 -0
- pykara-0.0.1/src/pykara/helpers/timeline.py +160 -0
- pykara-0.0.1/src/pykara/helpers/timeline_parsing.py +223 -0
- pykara-0.0.1/src/pykara/karaoke/__init__.py +20 -0
- pykara-0.0.1/src/pykara/karaoke/char.py +112 -0
- pykara-0.0.1/src/pykara/karaoke/line.py +62 -0
- pykara-0.0.1/src/pykara/karaoke/override_tags.py +73 -0
- pykara-0.0.1/src/pykara/karaoke/parser.py +340 -0
- pykara-0.0.1/src/pykara/karaoke/syllable.py +77 -0
- pykara-0.0.1/src/pykara/karaoke/word.py +148 -0
- pykara-0.0.1/src/pykara/layout/__init__.py +26 -0
- pykara-0.0.1/src/pykara/layout/_pango_measure.py +90 -0
- pykara-0.0.1/src/pykara/layout/_win32_measure.py +204 -0
- pykara-0.0.1/src/pykara/layout/positioning.py +399 -0
- pykara-0.0.1/src/pykara/layout/style.py +136 -0
- pykara-0.0.1/src/pykara/layout/text_measure.py +83 -0
- pykara-0.0.1/src/pykara/math/__init__.py +1 -0
- pykara-0.0.1/src/pykara/math/curves.py +57 -0
- pykara-0.0.1/src/pykara/motion/__init__.py +1 -0
- pykara-0.0.1/src/pykara/motion/arc/__init__.py +1 -0
- pykara-0.0.1/src/pykara/motion/arc/curve.py +27 -0
- pykara-0.0.1/src/pykara/motion/arc/fbf.py +56 -0
- pykara-0.0.1/src/pykara/motion/arc/request.py +50 -0
- pykara-0.0.1/src/pykara/motion/arc/shad.py +66 -0
- pykara-0.0.1/src/pykara/motion/bezier/__init__.py +1 -0
- pykara-0.0.1/src/pykara/motion/bezier/curve.py +35 -0
- pykara-0.0.1/src/pykara/motion/bezier/fbf.py +38 -0
- pykara-0.0.1/src/pykara/motion/bezier/request.py +36 -0
- pykara-0.0.1/src/pykara/motion/bezier/shad.py +49 -0
- pykara-0.0.1/src/pykara/motion/jitter/__init__.py +1 -0
- pykara-0.0.1/src/pykara/motion/jitter/engine.py +90 -0
- pykara-0.0.1/src/pykara/motion/jitter/fbf.py +100 -0
- pykara-0.0.1/src/pykara/motion/jitter/request.py +44 -0
- pykara-0.0.1/src/pykara/motion/jitter/shad.py +69 -0
- pykara-0.0.1/src/pykara/motion/jitter/spec.py +46 -0
- pykara-0.0.1/src/pykara/motion/runtime/__init__.py +2 -0
- pykara-0.0.1/src/pykara/motion/runtime/fbf/__init__.py +1 -0
- pykara-0.0.1/src/pykara/motion/runtime/fbf/ass_tags.py +943 -0
- pykara-0.0.1/src/pykara/motion/runtime/fbf/expansion.py +157 -0
- pykara-0.0.1/src/pykara/motion/runtime/fbf/protocol.py +21 -0
- pykara-0.0.1/src/pykara/motion/runtime/fbf/timeline.py +65 -0
- pykara-0.0.1/src/pykara/motion/runtime/runtime_geometry.py +26 -0
- pykara-0.0.1/src/pykara/motion/runtime/shad/__init__.py +1 -0
- pykara-0.0.1/src/pykara/motion/runtime/shad/formatting.py +19 -0
- pykara-0.0.1/src/pykara/motion/runtime/shad/transforms.py +9 -0
- pykara-0.0.1/src/pykara/motion/runtime/window.py +28 -0
- pykara-0.0.1/src/pykara/motion/spring/__init__.py +1 -0
- pykara-0.0.1/src/pykara/motion/spring/curve.py +24 -0
- pykara-0.0.1/src/pykara/motion/spring/fbf.py +50 -0
- pykara-0.0.1/src/pykara/motion/spring/request.py +48 -0
- pykara-0.0.1/src/pykara/motion/spring/shad.py +60 -0
- pykara-0.0.1/src/pykara/motion/wave/__init__.py +1 -0
- pykara-0.0.1/src/pykara/motion/wave/curve.py +23 -0
- pykara-0.0.1/src/pykara/motion/wave/fbf.py +51 -0
- pykara-0.0.1/src/pykara/motion/wave/request.py +46 -0
- pykara-0.0.1/src/pykara/motion/wave/shad.py +61 -0
- pykara-0.0.1/src/pykara/py.typed +1 -0
- pykara-0.0.1/src/pykara/timing/__init__.py +13 -0
- pykara-0.0.1/src/pykara/timing/framerate.py +298 -0
- pykara-0.0.1/tests/__init__.py +1 -0
- pykara-0.0.1/tests/acceptance/test_fixtures.py +158 -0
- pykara-0.0.1/tests/conftest.py +76 -0
- pykara-0.0.1/tests/fixtures/acceptance/01_foundations/basic_01_grow_larger.ass +121 -0
- pykara-0.0.1/tests/fixtures/acceptance/01_foundations/basic_02_appear_left_to_right_syllable.ass +120 -0
- pykara-0.0.1/tests/fixtures/acceptance/01_foundations/basic_03_appear_left_to_right_character.ass +298 -0
- pykara-0.0.1/tests/fixtures/acceptance/01_foundations/basic_04_show_one_object_per_line.ass +123 -0
- pykara-0.0.1/tests/fixtures/acceptance/01_foundations/basic_05_random_color_memory.ass +121 -0
- pykara-0.0.1/tests/fixtures/acceptance/01_foundations/basic_06_random_color_line_state.ass +122 -0
- pykara-0.0.1/tests/fixtures/acceptance/01_foundations/basic_07_move_shape_between_syllables.ass +160 -0
- pykara-0.0.1/tests/fixtures/acceptance/01_foundations/basic_08_jumping_effect.ass +118 -0
- pykara-0.0.1/tests/fixtures/acceptance/01_foundations/basic_25_vertical_karaoke.ass +115 -0
- pykara-0.0.1/tests/fixtures/acceptance/01_foundations/basic_26_repeat_single_loop.ass +16 -0
- pykara-0.0.1/tests/fixtures/acceptance/01_foundations/basic_27_repeat_named_cartesian.ass +19 -0
- pykara-0.0.1/tests/fixtures/acceptance/02_selection_and_color/basic_09_multi_highlight_ruby.ass +125 -0
- pykara-0.0.1/tests/fixtures/acceptance/02_selection_and_color/basic_10_select_effects_by_k_tag.ass +125 -0
- pykara-0.0.1/tests/fixtures/acceptance/02_selection_and_color/basic_11_select_effects_by_inline_fx.ass +124 -0
- pykara-0.0.1/tests/fixtures/acceptance/02_selection_and_color/basic_12_select_line_effects_by_actor.ass +119 -0
- pykara-0.0.1/tests/fixtures/acceptance/02_selection_and_color/basic_13_select_line_effects_by_when.ass +123 -0
- pykara-0.0.1/tests/fixtures/acceptance/02_selection_and_color/basic_14_alternating_color_syllable.ass +120 -0
- pykara-0.0.1/tests/fixtures/acceptance/02_selection_and_color/basic_15_alternating_color_character.ass +260 -0
- pykara-0.0.1/tests/fixtures/acceptance/02_selection_and_color/basic_16_color_from_hex.ass +25 -0
- pykara-0.0.1/tests/fixtures/acceptance/03_transitions/basic_16_transition_fade_in_center_to_sides.ass +163 -0
- pykara-0.0.1/tests/fixtures/acceptance/03_transitions/basic_17_transition_fade_in_left_to_right.ass +163 -0
- pykara-0.0.1/tests/fixtures/acceptance/03_transitions/basic_18_transition_fade_in_right_to_left.ass +162 -0
- pykara-0.0.1/tests/fixtures/acceptance/03_transitions/basic_19_transition_flash_left_to_right.ass +163 -0
- pykara-0.0.1/tests/fixtures/acceptance/03_transitions/basic_20_transition_flash_center_to_sides.ass +163 -0
- pykara-0.0.1/tests/fixtures/acceptance/03_transitions/basic_21_transition_flash_sides_to_center.ass +162 -0
- pykara-0.0.1/tests/fixtures/acceptance/03_transitions/basic_22_transition_rainbow_flash.ass +162 -0
- pykara-0.0.1/tests/fixtures/acceptance/03_transitions/basic_23_auto_translucent_background.ass +145 -0
- pykara-0.0.1/tests/fixtures/acceptance/03_transitions/basic_28_timeline_transitions.ass +25 -0
- pykara-0.0.1/tests/fixtures/acceptance/03_transitions/basic_29_motion_shadow_trick.ass +25 -0
- pykara-0.0.1/tests/fixtures/acceptance/03_transitions/basic_30_motion_jitter_shadow_trick.ass +25 -0
- pykara-0.0.1/tests/fixtures/acceptance/03_transitions/basic_31_timeline_pulse.ass +25 -0
- pykara-0.0.1/tests/fixtures/acceptance/04_stateful/basic_24_code_line_palette_helper.ass +149 -0
- pykara-0.0.1/tests/fixtures/acceptance/04_stateful/basic_25_timeline_sequence_palette_helper.ass +149 -0
- pykara-0.0.1/tests/fixtures/acceptance/99_invalid/retime_preset_matrix.ass +959 -0
- pykara-0.0.1/tests/fixtures/ass/cli_generated_fx_input.ass +13 -0
- pykara-0.0.1/tests/fixtures/ass/cli_timecodes_input.ass +13 -0
- pykara-0.0.1/tests/fixtures/ass/comment_event.ass +10 -0
- pykara-0.0.1/tests/fixtures/ass/event_before_format.ass +2 -0
- pykara-0.0.1/tests/fixtures/ass/event_missing_fields.ass +3 -0
- pykara-0.0.1/tests/fixtures/ass/events_with_comment.ass +4 -0
- pykara-0.0.1/tests/fixtures/ass/invalid_event_line.ass +3 -0
- pykara-0.0.1/tests/fixtures/ass/invalid_events_line.ass +2 -0
- pykara-0.0.1/tests/fixtures/ass/invalid_script_info_line.ass +2 -0
- pykara-0.0.1/tests/fixtures/ass/invalid_style_line.ass +3 -0
- pykara-0.0.1/tests/fixtures/ass/karaoke_inline_fx.ass +10 -0
- pykara-0.0.1/tests/fixtures/ass/reordered_format.ass +16 -0
- pykara-0.0.1/tests/fixtures/ass/style_before_format.ass +2 -0
- pykara-0.0.1/tests/fixtures/ass/style_missing_fields.ass +3 -0
- pykara-0.0.1/tests/fixtures/ass/styles_with_extra_column.ass +3 -0
- pykara-0.0.1/tests/fixtures/ass/unsupported_event_type.ass +3 -0
- pykara-0.0.1/tests/fixtures/ass/unsupported_styles_line.ass +3 -0
- pykara-0.0.1/tests/fixtures/reference/karaoke/karaoke.ass +28 -0
- pykara-0.0.1/tests/fixtures/reference/karaoke/karaoke_expected.json +47 -0
- pykara-0.0.1/tests/fixtures/reference/layout/layout.ass +27 -0
- pykara-0.0.1/tests/fixtures/reference/layout/text_measure.json +18 -0
- pykara-0.0.1/tests/fixtures/timecodes/crf_timecodes.txt +481 -0
- pykara-0.0.1/tests/fixtures/timecodes/vrf_timecodes.txt +116045 -0
- pykara-0.0.1/tests/fonts/Arial.ttf +0 -0
- pykara-0.0.1/tests/fonts/DroidSans-Bold.ttf +0 -0
- pykara-0.0.1/tests/fonts/DroidSans.ttf +0 -0
- pykara-0.0.1/tests/integration/test_collector.py +94 -0
- pykara-0.0.1/tests/integration/test_execution_runtime.py +702 -0
- pykara-0.0.1/tests/integration/test_runner_layout.py +69 -0
- pykara-0.0.1/tests/integration/test_runner_simple.py +693 -0
- pykara-0.0.1/tests/support/__init__.py +19 -0
- pykara-0.0.1/tests/support/builders.py +195 -0
- pykara-0.0.1/tests/unit/test_ass_error_paths.py +79 -0
- pykara-0.0.1/tests/unit/test_ass_parser.py +111 -0
- pykara-0.0.1/tests/unit/test_ass_time.py +16 -0
- pykara-0.0.1/tests/unit/test_ass_types.py +16 -0
- pykara-0.0.1/tests/unit/test_ass_writer.py +45 -0
- pykara-0.0.1/tests/unit/test_char.py +29 -0
- pykara-0.0.1/tests/unit/test_cli.py +119 -0
- pykara-0.0.1/tests/unit/test_directive_error_paths.py +56 -0
- pykara-0.0.1/tests/unit/test_directive_parser.py +222 -0
- pykara-0.0.1/tests/unit/test_directive_validator.py +315 -0
- pykara-0.0.1/tests/unit/test_evaluator.py +19 -0
- pykara-0.0.1/tests/unit/test_expression_catalog.py +207 -0
- pykara-0.0.1/tests/unit/test_framerate.py +331 -0
- pykara-0.0.1/tests/unit/test_helpers_color.py +86 -0
- pykara-0.0.1/tests/unit/test_helpers_memory.py +28 -0
- pykara-0.0.1/tests/unit/test_helpers_motion.py +159 -0
- pykara-0.0.1/tests/unit/test_helpers_motion_arc.py +96 -0
- pykara-0.0.1/tests/unit/test_helpers_motion_bezier.py +130 -0
- pykara-0.0.1/tests/unit/test_helpers_motion_spring.py +125 -0
- pykara-0.0.1/tests/unit/test_helpers_motion_wave.py +118 -0
- pykara-0.0.1/tests/unit/test_helpers_palette.py +73 -0
- pykara-0.0.1/tests/unit/test_helpers_relayer.py +81 -0
- pykara-0.0.1/tests/unit/test_helpers_retime.py +476 -0
- pykara-0.0.1/tests/unit/test_helpers_scale.py +55 -0
- pykara-0.0.1/tests/unit/test_helpers_timeline.py +353 -0
- pykara-0.0.1/tests/unit/test_interpolator.py +163 -0
- pykara-0.0.1/tests/unit/test_karaoke_error_paths.py +82 -0
- pykara-0.0.1/tests/unit/test_karaoke_line.py +20 -0
- pykara-0.0.1/tests/unit/test_karaoke_multi.py +19 -0
- pykara-0.0.1/tests/unit/test_karaoke_parser.py +53 -0
- pykara-0.0.1/tests/unit/test_layout_positioning.py +351 -0
- pykara-0.0.1/tests/unit/test_layout_text_measure.py +672 -0
- pykara-0.0.1/tests/unit/test_loop.py +134 -0
- pykara-0.0.1/tests/unit/test_math_curves.py +109 -0
- pykara-0.0.1/tests/unit/test_motion_arc_fbf.py +55 -0
- pykara-0.0.1/tests/unit/test_motion_arc_shad.py +67 -0
- pykara-0.0.1/tests/unit/test_motion_bezier_fbf.py +75 -0
- pykara-0.0.1/tests/unit/test_motion_bezier_shad.py +59 -0
- pykara-0.0.1/tests/unit/test_motion_constraints.py +71 -0
- pykara-0.0.1/tests/unit/test_motion_fbf.py +1225 -0
- pykara-0.0.1/tests/unit/test_motion_jitter_fbf.py +104 -0
- pykara-0.0.1/tests/unit/test_motion_spring_fbf.py +71 -0
- pykara-0.0.1/tests/unit/test_motion_spring_shad.py +53 -0
- pykara-0.0.1/tests/unit/test_motion_wave_fbf.py +79 -0
- pykara-0.0.1/tests/unit/test_motion_wave_shad.py +64 -0
- pykara-0.0.1/tests/unit/test_override_tags.py +23 -0
- pykara-0.0.1/tests/unit/test_preflight.py +353 -0
- pykara-0.0.1/tests/unit/test_retime_state.py +155 -0
- pykara-0.0.1/tests/unit/test_syllable.py +20 -0
- pykara-0.0.1/tests/unit/test_word.py +23 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
env:
|
|
11
|
+
PYTHON_VERSION: "3.11"
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
quality:
|
|
15
|
+
name: Quality
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- name: Check out repository
|
|
20
|
+
uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
uses: actions/setup-python@v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
26
|
+
cache: "pip"
|
|
27
|
+
|
|
28
|
+
- name: Install system dependencies
|
|
29
|
+
run: |
|
|
30
|
+
sudo apt-get update
|
|
31
|
+
sudo apt-get install -y \
|
|
32
|
+
libcairo2-dev \
|
|
33
|
+
libgirepository-2.0-dev \
|
|
34
|
+
gir1.2-pango-1.0 \
|
|
35
|
+
pkg-config
|
|
36
|
+
|
|
37
|
+
- name: Install Python dependencies
|
|
38
|
+
run: |
|
|
39
|
+
python -m pip install --upgrade pip
|
|
40
|
+
python -m pip install .[dev]
|
|
41
|
+
|
|
42
|
+
- name: Run Ruff
|
|
43
|
+
run: python -m ruff check src tests
|
|
44
|
+
|
|
45
|
+
- name: Generate Pyright CI config
|
|
46
|
+
run: |
|
|
47
|
+
python - <<'PY'
|
|
48
|
+
import json
|
|
49
|
+
import site
|
|
50
|
+
|
|
51
|
+
config = {
|
|
52
|
+
"include": ["src", "tests"],
|
|
53
|
+
"typeCheckingMode": "strict",
|
|
54
|
+
"pythonVersion": "3.11",
|
|
55
|
+
"extraPaths": [".", "src", site.getsitepackages()[0]],
|
|
56
|
+
"executionEnvironments": [
|
|
57
|
+
{
|
|
58
|
+
"root": "tests",
|
|
59
|
+
"reportUnknownMemberType": "none",
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
with open("pyright-ci.json", "w", encoding="utf-8") as file:
|
|
65
|
+
json.dump(config, file, indent=2)
|
|
66
|
+
PY
|
|
67
|
+
|
|
68
|
+
- name: Run Pyright
|
|
69
|
+
run: python -m pyright -p pyright-ci.json
|
|
70
|
+
|
|
71
|
+
- name: Run Rumdl
|
|
72
|
+
run: rumdl check README.md $(find docs -name '*.md' -type f | sort)
|
|
73
|
+
|
|
74
|
+
tests:
|
|
75
|
+
name: Tests
|
|
76
|
+
runs-on: ubuntu-latest
|
|
77
|
+
|
|
78
|
+
steps:
|
|
79
|
+
- name: Check out repository
|
|
80
|
+
uses: actions/checkout@v4
|
|
81
|
+
|
|
82
|
+
- name: Set up Python
|
|
83
|
+
uses: actions/setup-python@v5
|
|
84
|
+
with:
|
|
85
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
86
|
+
cache: "pip"
|
|
87
|
+
|
|
88
|
+
- name: Install system dependencies
|
|
89
|
+
run: |
|
|
90
|
+
sudo apt-get update
|
|
91
|
+
sudo apt-get install -y \
|
|
92
|
+
libcairo2-dev \
|
|
93
|
+
libgirepository-2.0-dev \
|
|
94
|
+
gir1.2-pango-1.0 \
|
|
95
|
+
pkg-config
|
|
96
|
+
|
|
97
|
+
- name: Install Python dependencies
|
|
98
|
+
run: |
|
|
99
|
+
python -m pip install --upgrade pip
|
|
100
|
+
python -m pip install .[dev]
|
|
101
|
+
|
|
102
|
+
- name: Run Pytest
|
|
103
|
+
run: python -m pytest
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: Package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
env:
|
|
12
|
+
PYTHON_VERSION: "3.11"
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
build-distributions:
|
|
16
|
+
name: Build distributions
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- name: Check out repository
|
|
21
|
+
uses: actions/checkout@v6
|
|
22
|
+
with:
|
|
23
|
+
persist-credentials: false
|
|
24
|
+
|
|
25
|
+
- name: Set up Python
|
|
26
|
+
uses: actions/setup-python@v6
|
|
27
|
+
with:
|
|
28
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
29
|
+
cache: "pip"
|
|
30
|
+
|
|
31
|
+
- name: Install packaging tools
|
|
32
|
+
run: |
|
|
33
|
+
python -m pip install --upgrade pip
|
|
34
|
+
python -m pip install build twine
|
|
35
|
+
|
|
36
|
+
- name: Build wheel and sdist
|
|
37
|
+
run: python -m build
|
|
38
|
+
|
|
39
|
+
- name: Check distribution metadata
|
|
40
|
+
run: python -m twine check --strict dist/*
|
|
41
|
+
|
|
42
|
+
- name: Store distribution packages
|
|
43
|
+
uses: actions/upload-artifact@v5
|
|
44
|
+
with:
|
|
45
|
+
name: python-package-distributions
|
|
46
|
+
path: dist/
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
- "*.*.*"
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
env:
|
|
13
|
+
PYTHON_VERSION: "3.11"
|
|
14
|
+
PYPI_PACKAGE_NAME: "pykara"
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
build:
|
|
18
|
+
name: Build distributions
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- name: Check out repository
|
|
23
|
+
uses: actions/checkout@v6
|
|
24
|
+
with:
|
|
25
|
+
persist-credentials: false
|
|
26
|
+
|
|
27
|
+
- name: Set up Python
|
|
28
|
+
uses: actions/setup-python@v6
|
|
29
|
+
with:
|
|
30
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
31
|
+
cache: "pip"
|
|
32
|
+
|
|
33
|
+
- name: Install packaging tools
|
|
34
|
+
run: |
|
|
35
|
+
python -m pip install --upgrade pip
|
|
36
|
+
python -m pip install build twine
|
|
37
|
+
|
|
38
|
+
- name: Build wheel and sdist
|
|
39
|
+
run: python -m build
|
|
40
|
+
|
|
41
|
+
- name: Check distribution metadata
|
|
42
|
+
run: python -m twine check --strict dist/*
|
|
43
|
+
|
|
44
|
+
- name: Store distribution packages
|
|
45
|
+
uses: actions/upload-artifact@v5
|
|
46
|
+
with:
|
|
47
|
+
name: python-package-distributions
|
|
48
|
+
path: dist/
|
|
49
|
+
|
|
50
|
+
publish-to-pypi:
|
|
51
|
+
name: Publish to PyPI
|
|
52
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
53
|
+
needs:
|
|
54
|
+
- build
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
environment:
|
|
57
|
+
name: pypi
|
|
58
|
+
url: https://pypi.org/p/${{ env.PYPI_PACKAGE_NAME }}
|
|
59
|
+
permissions:
|
|
60
|
+
id-token: write
|
|
61
|
+
|
|
62
|
+
steps:
|
|
63
|
+
- name: Download distribution packages
|
|
64
|
+
uses: actions/download-artifact@v6
|
|
65
|
+
with:
|
|
66
|
+
name: python-package-distributions
|
|
67
|
+
path: dist/
|
|
68
|
+
|
|
69
|
+
- name: Publish distribution
|
|
70
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
pykara-0.0.1/.gitignore
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Python bytecode and caches
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
|
|
7
|
+
# Virtual environments
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
impl/.venv/
|
|
11
|
+
|
|
12
|
+
# Packaging artifacts
|
|
13
|
+
build/
|
|
14
|
+
dist/
|
|
15
|
+
*.egg-info/
|
|
16
|
+
.eggs/
|
|
17
|
+
pip-wheel-metadata/
|
|
18
|
+
|
|
19
|
+
# Test and lint caches
|
|
20
|
+
.pytest_cache/
|
|
21
|
+
.ruff_cache/
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
.pyright/
|
|
24
|
+
.pyrightcache/
|
|
25
|
+
.coverage
|
|
26
|
+
.coverage.*
|
|
27
|
+
htmlcov/
|
|
28
|
+
.rumdl_cache/
|
|
29
|
+
|
|
30
|
+
# Local tooling and editor files
|
|
31
|
+
.DS_Store
|
|
32
|
+
.idea/
|
|
33
|
+
.vscode/
|
|
34
|
+
.codex
|
|
35
|
+
.claude
|
|
36
|
+
.agents
|
pykara-0.0.1/.rumdl.toml
ADDED
pykara-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pykara
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Standalone Python CLI karaoke templater.
|
|
5
|
+
Project-URL: Homepage, https://github.com/pandafansub/pykara
|
|
6
|
+
Project-URL: Documentation, https://github.com/pandafansub/pykara/blob/main/docs/index.md
|
|
7
|
+
Project-URL: Repository, https://github.com/pandafansub/pykara
|
|
8
|
+
Project-URL: Issues, https://github.com/pandafansub/pykara/issues
|
|
9
|
+
Author-email: Panda Fansub <contato@pandafansub.com>
|
|
10
|
+
Keywords: aegisub,ass,karaoke,subtitles
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Topic :: Multimedia :: Video
|
|
18
|
+
Classifier: Topic :: Text Processing
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Requires-Dist: pycairo
|
|
21
|
+
Requires-Dist: pygobject
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: build; extra == 'dev'
|
|
24
|
+
Requires-Dist: coverage; extra == 'dev'
|
|
25
|
+
Requires-Dist: pyright; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
28
|
+
Requires-Dist: rumdl; extra == 'dev'
|
|
29
|
+
Requires-Dist: twine; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# pykara
|
|
33
|
+
|
|
34
|
+
Standalone Python CLI karaoke templater for ASS subtitles.
|
|
35
|
+
|
|
36
|
+
## Requirements
|
|
37
|
+
|
|
38
|
+
- Python 3.11+
|
|
39
|
+
- Cairo and Pango bindings available to Python
|
|
40
|
+
|
|
41
|
+
On Ubuntu/Debian, the CI setup installs:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
sudo apt-get install -y \
|
|
45
|
+
libcairo2-dev \
|
|
46
|
+
libgirepository-2.0-dev \
|
|
47
|
+
gir1.2-pango-1.0 \
|
|
48
|
+
pkg-config
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Install
|
|
52
|
+
|
|
53
|
+
Install from PyPI:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
python -m pip install pykara
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The package name on PyPI is `pykara`. The CLI command remains
|
|
60
|
+
`pykara`.
|
|
61
|
+
|
|
62
|
+
For a source checkout with development tools:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
python -m pip install -e .[dev]
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Documentation
|
|
69
|
+
|
|
70
|
+
Start with the
|
|
71
|
+
[documentation index](https://github.com/pandafansub/pykara/blob/main/docs/index.md)
|
|
72
|
+
for directives, scopes, and helpers.
|
|
73
|
+
|
|
74
|
+
## CLI
|
|
75
|
+
|
|
76
|
+
Write a new `.ass` output file:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pykara input.ass output.ass
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Print only the generated ASS event rows:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pykara --emit-events input.ass
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Use timecodes for frame-baked motion:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pykara --timecodes path/to/timecodes.txt input.ass output.ass
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Useful flags:
|
|
95
|
+
|
|
96
|
+
- `--seed`: deterministic RNG seed for reproducible output
|
|
97
|
+
- `--debug`: show the full traceback instead of the short CLI error
|
|
98
|
+
|
|
99
|
+
## Aegisub Bridge
|
|
100
|
+
|
|
101
|
+
The repository includes an Aegisub automation script at
|
|
102
|
+
`bridge/pykara.lua`.
|
|
103
|
+
|
|
104
|
+
The bridge expects the `pykara` command to be available in `PATH`, runs
|
|
105
|
+
`pykara --emit-events` for the currently open subtitle file, removes existing
|
|
106
|
+
`fx` lines, inserts the regenerated ones, and comments the source karaoke
|
|
107
|
+
lines.
|
pykara-0.0.1/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# pykara
|
|
2
|
+
|
|
3
|
+
Standalone Python CLI karaoke templater for ASS subtitles.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Python 3.11+
|
|
8
|
+
- Cairo and Pango bindings available to Python
|
|
9
|
+
|
|
10
|
+
On Ubuntu/Debian, the CI setup installs:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
sudo apt-get install -y \
|
|
14
|
+
libcairo2-dev \
|
|
15
|
+
libgirepository-2.0-dev \
|
|
16
|
+
gir1.2-pango-1.0 \
|
|
17
|
+
pkg-config
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
Install from PyPI:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
python -m pip install pykara
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The package name on PyPI is `pykara`. The CLI command remains
|
|
29
|
+
`pykara`.
|
|
30
|
+
|
|
31
|
+
For a source checkout with development tools:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
python -m pip install -e .[dev]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Documentation
|
|
38
|
+
|
|
39
|
+
Start with the
|
|
40
|
+
[documentation index](https://github.com/pandafansub/pykara/blob/main/docs/index.md)
|
|
41
|
+
for directives, scopes, and helpers.
|
|
42
|
+
|
|
43
|
+
## CLI
|
|
44
|
+
|
|
45
|
+
Write a new `.ass` output file:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pykara input.ass output.ass
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Print only the generated ASS event rows:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pykara --emit-events input.ass
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Use timecodes for frame-baked motion:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pykara --timecodes path/to/timecodes.txt input.ass output.ass
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Useful flags:
|
|
64
|
+
|
|
65
|
+
- `--seed`: deterministic RNG seed for reproducible output
|
|
66
|
+
- `--debug`: show the full traceback instead of the short CLI error
|
|
67
|
+
|
|
68
|
+
## Aegisub Bridge
|
|
69
|
+
|
|
70
|
+
The repository includes an Aegisub automation script at
|
|
71
|
+
`bridge/pykara.lua`.
|
|
72
|
+
|
|
73
|
+
The bridge expects the `pykara` command to be available in `PATH`, runs
|
|
74
|
+
`pykara --emit-events` for the currently open subtitle file, removes existing
|
|
75
|
+
`fx` lines, inserts the regenerated ones, and comments the source karaoke
|
|
76
|
+
lines.
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
script_name = "pykara Bridge"
|
|
2
|
+
script_description = "Run pykara and insert generated FX lines"
|
|
3
|
+
script_author = "pykara"
|
|
4
|
+
script_version = "1.0"
|
|
5
|
+
|
|
6
|
+
local function is_windows()
|
|
7
|
+
return package.config:sub(1, 1) == "\\"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
local function shell_quote(value)
|
|
11
|
+
if is_windows() then
|
|
12
|
+
return '"' .. tostring(value):gsub('"', '""') .. '"'
|
|
13
|
+
end
|
|
14
|
+
return "'" .. tostring(value):gsub("'", "'\\''") .. "'"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
local function join_path(...)
|
|
18
|
+
local separator = is_windows() and "\\" or "/"
|
|
19
|
+
local parts = {...}
|
|
20
|
+
return table.concat(parts, separator)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
local function parse_ass_time(value)
|
|
24
|
+
local hours, minutes, seconds, centiseconds =
|
|
25
|
+
value:match("^(%d+):(%d%d):(%d%d)%.(%d%d)$")
|
|
26
|
+
if not hours then
|
|
27
|
+
error("Invalid ASS time: " .. tostring(value))
|
|
28
|
+
end
|
|
29
|
+
return (
|
|
30
|
+
(((tonumber(hours) * 60) + tonumber(minutes)) * 60 + tonumber(seconds))
|
|
31
|
+
* 1000
|
|
32
|
+
) + tonumber(centiseconds) * 10
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
local function split_event_fields(value)
|
|
36
|
+
local fields = {}
|
|
37
|
+
local rest = value
|
|
38
|
+
for _ = 1, 9 do
|
|
39
|
+
local current, next_rest = rest:match("^([^,]*),(.*)$")
|
|
40
|
+
if not current then
|
|
41
|
+
break
|
|
42
|
+
end
|
|
43
|
+
table.insert(fields, current)
|
|
44
|
+
rest = next_rest
|
|
45
|
+
end
|
|
46
|
+
table.insert(fields, rest)
|
|
47
|
+
return fields
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
local function parse_generated_line(raw_line)
|
|
51
|
+
local kind, body = raw_line:match("^(%a+):%s*(.*)$")
|
|
52
|
+
if kind ~= "Dialogue" and kind ~= "Comment" then
|
|
53
|
+
error("Unexpected generated event line: " .. tostring(raw_line))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
local fields = split_event_fields(body)
|
|
57
|
+
return {
|
|
58
|
+
class = "dialogue",
|
|
59
|
+
section = "[Events]",
|
|
60
|
+
comment = kind == "Comment",
|
|
61
|
+
layer = tonumber(fields[1]) or 0,
|
|
62
|
+
start_time = parse_ass_time(fields[2] or "0:00:00.00"),
|
|
63
|
+
end_time = parse_ass_time(fields[3] or "0:00:00.00"),
|
|
64
|
+
style = fields[4] or "",
|
|
65
|
+
actor = fields[5] or "",
|
|
66
|
+
margin_l = tonumber(fields[6]) or 0,
|
|
67
|
+
margin_r = tonumber(fields[7]) or 0,
|
|
68
|
+
margin_t = tonumber(fields[8]) or 0,
|
|
69
|
+
margin_b = tonumber(fields[8]) or 0,
|
|
70
|
+
effect = fields[9] or "",
|
|
71
|
+
text = fields[10] or "",
|
|
72
|
+
raw = raw_line,
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
local function current_ass_path()
|
|
77
|
+
local dir = aegisub.decode_path("?script")
|
|
78
|
+
local name = aegisub.file_name()
|
|
79
|
+
|
|
80
|
+
if not dir or dir == "" or not name or name == "" then
|
|
81
|
+
return nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
return join_path(dir, name)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
local function pykara_command()
|
|
88
|
+
return "pykara --emit-events "
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
local function show_text_dialog(text)
|
|
92
|
+
aegisub.dialog.display({
|
|
93
|
+
{
|
|
94
|
+
class = "textbox",
|
|
95
|
+
x = 0,
|
|
96
|
+
y = 0,
|
|
97
|
+
width = 60,
|
|
98
|
+
height = 10,
|
|
99
|
+
text = text,
|
|
100
|
+
}
|
|
101
|
+
}, {"OK"})
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
local function show_missing_pykara_message(output)
|
|
105
|
+
local message = table.concat({
|
|
106
|
+
"The `pykara` command is not available in PATH.",
|
|
107
|
+
"",
|
|
108
|
+
"Install it in your environment and ensure the command is available.",
|
|
109
|
+
"",
|
|
110
|
+
"Command output:",
|
|
111
|
+
output,
|
|
112
|
+
}, "\n")
|
|
113
|
+
show_text_dialog(message)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
local function strip_ansi(text)
|
|
117
|
+
return (text or ""):gsub("\27%[[%d;]*m", "")
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
local function normalize_output_lines(output)
|
|
121
|
+
local cleaned = strip_ansi(output)
|
|
122
|
+
local lines = {}
|
|
123
|
+
for raw_line in cleaned:gmatch("[^\r\n]+") do
|
|
124
|
+
local line = raw_line:gsub("%s+$", "")
|
|
125
|
+
if line ~= "" then
|
|
126
|
+
table.insert(lines, line)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
return lines
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
local function try_bridge_command(command)
|
|
133
|
+
local pipe = io.popen(command .. " 2>&1")
|
|
134
|
+
|
|
135
|
+
if not pipe then
|
|
136
|
+
return false, "io.popen failed in this Aegisub build.", false
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
local output = pipe:read("*a") or ""
|
|
140
|
+
local ok = pipe:close()
|
|
141
|
+
|
|
142
|
+
return ok ~= nil, output, true
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
local function remove_existing_fx_lines(subs)
|
|
146
|
+
for i = #subs, 1, -1 do
|
|
147
|
+
local line = subs[i]
|
|
148
|
+
if line.class == "dialogue" and not line.comment and line.effect == "fx" then
|
|
149
|
+
subs.delete(i)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
local function comment_input_lines(subs)
|
|
155
|
+
for i = 1, #subs do
|
|
156
|
+
local line = subs[i]
|
|
157
|
+
if line.class == "dialogue" and not line.comment then
|
|
158
|
+
local effect = (line.effect or ""):lower()
|
|
159
|
+
if effect == "kara" or effect == "karaoke" then
|
|
160
|
+
line.comment = true
|
|
161
|
+
subs[i] = line
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
local function run_bridge(subs)
|
|
168
|
+
local input_path = current_ass_path()
|
|
169
|
+
|
|
170
|
+
if not input_path then
|
|
171
|
+
aegisub.dialog.display({
|
|
172
|
+
{
|
|
173
|
+
class = "label",
|
|
174
|
+
x = 0,
|
|
175
|
+
y = 0,
|
|
176
|
+
width = 60,
|
|
177
|
+
height = 2,
|
|
178
|
+
label = "Could not resolve the current subtitle path.",
|
|
179
|
+
}
|
|
180
|
+
}, {"OK"})
|
|
181
|
+
return
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
local command = pykara_command() .. shell_quote(input_path)
|
|
185
|
+
local succeeded, output, command_started = try_bridge_command(command)
|
|
186
|
+
|
|
187
|
+
if not command_started then
|
|
188
|
+
aegisub.dialog.display({
|
|
189
|
+
{
|
|
190
|
+
class = "label",
|
|
191
|
+
x = 0,
|
|
192
|
+
y = 0,
|
|
193
|
+
width = 60,
|
|
194
|
+
height = 2,
|
|
195
|
+
label = "io.popen failed in this Aegisub build.",
|
|
196
|
+
}
|
|
197
|
+
}, {"OK"})
|
|
198
|
+
return
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
if not succeeded then
|
|
202
|
+
if output:match("command not found")
|
|
203
|
+
or output:match("not found")
|
|
204
|
+
or output:match("is not recognized as an internal or external command")
|
|
205
|
+
then
|
|
206
|
+
show_missing_pykara_message(output)
|
|
207
|
+
return
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
if output:match("No module named ['\"]pykara['\"]")
|
|
211
|
+
or output:match("ModuleNotFoundError:.-pykara")
|
|
212
|
+
then
|
|
213
|
+
show_missing_pykara_message(output)
|
|
214
|
+
return
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
local lines = normalize_output_lines(output)
|
|
218
|
+
if #lines > 0 then
|
|
219
|
+
show_text_dialog(table.concat(lines, "\n"))
|
|
220
|
+
else
|
|
221
|
+
show_text_dialog(output)
|
|
222
|
+
end
|
|
223
|
+
return
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
remove_existing_fx_lines(subs)
|
|
227
|
+
|
|
228
|
+
for raw_line in output:gmatch("[^\r\n]+") do
|
|
229
|
+
if raw_line:match("^Dialogue: ") or raw_line:match("^Comment: ") then
|
|
230
|
+
subs.append(parse_generated_line(raw_line))
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
comment_input_lines(subs)
|
|
235
|
+
|
|
236
|
+
aegisub.set_undo_point("pykara Apply Templates")
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
aegisub.register_macro(
|
|
240
|
+
"pykara Apply Templates",
|
|
241
|
+
"Generate FX lines through the Python bridge",
|
|
242
|
+
run_bridge
|
|
243
|
+
)
|